ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / isomgr.c
1 /*
2  * arch/arm/mach-tegra/isomgr.c
3  *
4  * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #define pr_fmt(fmt)     "%s %s(): " fmt, current->comm, __func__
21
22 #include <linux/delay.h>
23 #include <linux/types.h>
24 #include <linux/compiler.h>
25 #include <linux/kernel.h>
26 #include <linux/mutex.h>
27 #include <linux/completion.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
30 #include <linux/kobject.h>
31 #include <linux/sysfs.h>
32 #include <linux/printk.h>
33 #include <linux/clk.h>
34 #include <linux/err.h>
35 #include <linux/kref.h>
36 #include <linux/sched.h>
37 #include <linux/tegra-soc.h>
38 #include <asm/processor.h>
39 #include <asm/current.h>
40 #include <mach/isomgr.h>
41 #include <mach/mc.h>
42
43 #define CREATE_TRACE_POINTS
44 #include <trace/events/isomgr.h>
45
46 #define ISOMGR_SYSFS_VERSION 0  /* increment on change */
47 #define ISOMGR_DEBUG 1
48
49 #if ISOMGR_DEBUG
50 #define SANITY_CHECK_AVAIL_BW() { \
51         int t = 0; \
52         int idx = 0; \
53         for (idx = 0; idx < TEGRA_ISO_CLIENT_COUNT; idx++) { \
54                 if (isomgr_clients[idx].real_bw >= \
55                     isomgr_clients[idx].margin_bw) \
56                         t += isomgr_clients[idx].real_bw; \
57                 else \
58                         t += isomgr_clients[idx].margin_bw; \
59         } \
60         if (t + isomgr.avail_bw != isomgr.max_iso_bw) { \
61                 pr_err("bw mismatch, line=%d", __LINE__); \
62                 pr_err("t+isomgr.avail_bw=%d, isomgr.max_iso_bw=%d", \
63                         t + isomgr.avail_bw, isomgr.max_iso_bw); \
64                 BUG(); \
65         } \
66 }
67 #else
68 #define SANITY_CHECK_AVAIL_BW()
69 #endif
70
71 #define VALIDATE_HANDLE() \
72 do { \
73         if (unlikely(!cp || !is_client_valid(client) || \
74                      cp->magic != ISOMGR_MAGIC)) { \
75                 pr_err("bad handle %p", handle); \
76                 goto validation_fail; \
77         } \
78 } while (0)
79
80 #define VALIDATE_CLIENT() \
81 do { \
82         if (unlikely(!is_client_valid(client))) { \
83                 pr_err("invalid client %d", client); \
84                 goto validation_fail; \
85         } \
86 } while (0)
87
88 /* To allow test code take over control */
89 static bool test_mode;
90
91 static char *cname[] = {
92         "disp_0",
93         "disp_1",
94         "vi_0",
95         "vi_1",
96         "isp_a",
97         "isp_b",
98         "bbc_0",
99         "unknown"
100 };
101
102 struct isoclient_info {
103         enum tegra_iso_client client;
104         char *name;
105         char *dev_name;
106         char *emc_clk_name;
107 };
108
109 static struct isoclient_info *isoclient_info;
110 static bool client_valid[TEGRA_ISO_CLIENT_COUNT];
111 static int iso_bw_percentage = 100;
112
113 static struct isoclient_info tegra_null_isoclients[] = {
114         /* This must be last entry*/
115         {
116                 .client = TEGRA_ISO_CLIENT_COUNT,
117                 .name = NULL,
118         },
119 };
120
121 static struct isoclient_info tegra11x_isoclients[] = {
122         {
123                 .client = TEGRA_ISO_CLIENT_DISP_0,
124                 .name = "disp_0",
125                 .dev_name = "tegradc.0",
126                 .emc_clk_name = "emc",
127         },
128         {
129                 .client = TEGRA_ISO_CLIENT_DISP_1,
130                 .name = "disp_1",
131                 .dev_name = "tegradc.1",
132                 .emc_clk_name = "emc",
133         },
134         {
135                 .client = TEGRA_ISO_CLIENT_VI_0,
136                 .name = "vi_0",
137                 .dev_name = "vi",
138                 .emc_clk_name = "emc",
139         },
140         /* This must be last entry*/
141         {
142                 .client = TEGRA_ISO_CLIENT_COUNT,
143                 .name = NULL,
144         },
145 };
146
147 static struct isoclient_info tegra14x_isoclients[] = {
148         {
149                 .client = TEGRA_ISO_CLIENT_DISP_0,
150                 .name = "disp_0",
151                 .dev_name = "tegradc.0",
152                 .emc_clk_name = "emc",
153         },
154         {
155                 .client = TEGRA_ISO_CLIENT_DISP_1,
156                 .name = "disp_1",
157                 .dev_name = "tegradc.1",
158                 .emc_clk_name = "emc",
159         },
160         {
161                 .client = TEGRA_ISO_CLIENT_VI_0,
162                 .name = "vi_0",
163                 .dev_name = "vi",
164                 .emc_clk_name = "emc",
165         },
166         {
167                 .client = TEGRA_ISO_CLIENT_BBC_0,
168                 .name = "bbc_0",
169                 .dev_name = "tegra_bb.0",
170                 .emc_clk_name = "emc_bw",
171         },
172         /* This must be last entry*/
173         {
174                 .client = TEGRA_ISO_CLIENT_COUNT,
175                 .name = NULL,
176         },
177 };
178
179 static struct isoclient_info tegra12x_isoclients[] = {
180         {
181                 .client = TEGRA_ISO_CLIENT_DISP_0,
182                 .name = "disp_0",
183                 .dev_name = "tegradc.0",
184                 .emc_clk_name = "emc",
185         },
186         {
187                 .client = TEGRA_ISO_CLIENT_DISP_1,
188                 .name = "disp_1",
189                 .dev_name = "tegradc.1",
190                 .emc_clk_name = "emc",
191         },
192         {
193                 .client = TEGRA_ISO_CLIENT_VI_0,
194                 .name = "vi_0",
195                 .dev_name = "tegra_vi.0",
196                 .emc_clk_name = "emc",
197         },
198         {
199                 .client = TEGRA_ISO_CLIENT_VI_1,
200                 .name = "vi_1",
201                 .dev_name = "tegra_vi.1",
202                 .emc_clk_name = "emc",
203         },
204         {
205                 .client = TEGRA_ISO_CLIENT_ISP_A,
206                 .name = "isp_a",
207                 .dev_name = "tegra_isp.0",
208                 .emc_clk_name = "emc",
209         },
210         {
211                 .client = TEGRA_ISO_CLIENT_ISP_B,
212                 .name = "isp_b",
213                 .dev_name = "tegra_isp.1",
214                 .emc_clk_name = "emc",
215         },
216         /* This must be last entry*/
217         {
218                 .client = TEGRA_ISO_CLIENT_COUNT,
219                 .name = NULL,
220         },
221 };
222
223 static void isomgr_scatter(int client);
224
225 static struct isoclient_info *get_iso_client_info(void)
226 {
227         enum tegra_chipid cid;
228         struct isoclient_info *cinfo;
229
230         cid = tegra_get_chipid();
231         switch (cid) {
232         case TEGRA_CHIPID_TEGRA11:
233                 cinfo = tegra11x_isoclients;
234                 iso_bw_percentage = 50;
235                 break;
236         case TEGRA_CHIPID_TEGRA14:
237                 cinfo = tegra14x_isoclients;
238                 iso_bw_percentage = 50;
239                 break;
240         case TEGRA_CHIPID_TEGRA12:
241                 cinfo = tegra12x_isoclients;
242                 iso_bw_percentage = 44;
243                 break;
244         default:
245                 cinfo = tegra_null_isoclients;
246                 break;
247         }
248         return cinfo;
249 }
250
251 #define ISOMGR_MAGIC  0x150A1C
252 static struct isomgr_client {
253         u32 magic;              /* magic to identify handle */
254         struct kref kref;       /* ref counting */
255         s32 dedi_bw;            /* BW dedicated to this client  (KB/sec) */
256         s32 rsvd_bw;            /* BW reserved for this client  (KB/sec) */
257         s32 real_bw;            /* BW realized for this client  (KB/sec) */
258         s32 lti;                /* Client spec'd Latency Tolerance (usec) */
259         s32 lto;                /* MC calculated Latency Tolerance (usec) */
260         s32 rsvd_mf;            /* reserved minimum freq in support of LT */
261         s32 real_mf;            /* realized minimum freq in support of LT */
262         s32 real_mf_rq;         /* real_mf requested */
263         tegra_isomgr_renegotiate renegotiate;   /* ask client to renegotiate */
264         bool realize;           /* bw realization in progress */
265         s32 sleep_bw;           /* sleeping for realize */
266         s32 margin_bw;          /* BW set aside for this client (KB/sec) */
267         void *priv;             /* client driver's private data */
268         struct completion cmpl; /* so we can sleep waiting for delta BW */
269         struct clk *emc_clk;    /* client emc clk for bw */
270 #ifdef CONFIG_TEGRA_ISOMGR_SYSFS
271         struct kobject *client_kobj;
272         struct isomgr_client_attrs {
273                 struct kobj_attribute dedi_bw;
274                 struct kobj_attribute rsvd_bw;
275                 struct kobj_attribute real_bw;
276                 struct kobj_attribute lti;
277                 struct kobj_attribute lto;
278                 struct kobj_attribute rsvd_mf;
279                 struct kobj_attribute real_mf;
280                 struct kobj_attribute sleep_bw;
281                 struct kobj_attribute margin_bw;
282         } client_attrs;
283 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
284 } isomgr_clients[TEGRA_ISO_CLIENT_COUNT];
285
286 static struct {
287         struct mutex lock;              /* to lock ALL isomgr state */
288         struct task_struct *task;       /* check reentrant/mismatched locks */
289         struct clk *emc_clk;            /* isomgr emc clock for floor freq */
290         s32 lt_mf;                      /* min freq to support worst LT */
291         s32 lt_mf_rq;                   /* requested lt_mf */
292         s32 avail_bw;                   /* globally available MC BW */
293         s32 dedi_bw;                    /* total BW 'dedicated' to clients */
294         s32 sleep_bw;                   /* pending bw requirement */
295         u32 max_iso_bw;                 /* max ISO BW MC can accomodate */
296         struct kobject *kobj;           /* for sysfs linkage */
297 } isomgr = {
298         .max_iso_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
299         .avail_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
300 };
301
302 /* get minimum MC frequency for client that can support this BW and LT */
303 static inline u32 mc_min_freq(u32 ubw, u32 ult) /* in KB/sec and usec */
304 {
305         unsigned int min_freq = 0;
306
307         /* ult==0 means ignore LT (effectively infinite) */
308         if (ubw == 0)
309                 goto out;
310         min_freq = tegra_emc_bw_to_freq_req(ubw);
311 out:
312         return min_freq; /* return value in KHz*/
313 }
314
315 /* get dvfs switch latency for client requiring this frequency */
316 static inline u32 mc_dvfs_latency(u32 ufreq)
317 {
318         return tegra_emc_dvfs_latency(ufreq); /* return value in usec */
319 }
320
321 static inline void isomgr_lock(void)
322 {
323         BUG_ON(isomgr.task == current); /* disallow rentrance, avoid deadlock */
324         mutex_lock(&isomgr.lock);
325         isomgr.task = current;
326 }
327
328 static inline void isomgr_unlock(void)
329 {
330         BUG_ON(isomgr.task != current); /* detect mismatched calls */
331         isomgr.task = 0;
332         mutex_unlock(&isomgr.lock);
333 }
334
335 /* call with isomgr_lock held. */
336 static void update_mc_clock(void)
337 {
338         int i;
339
340         BUG_ON(mutex_trylock(&isomgr.lock));
341         /* determine worst case freq to satisfy LT */
342         isomgr.lt_mf = 0;
343         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
344                 isomgr.lt_mf = max(isomgr.lt_mf, isomgr_clients[i].real_mf);
345
346         /* request the floor freq to satisfy LT */
347         if (isomgr.lt_mf_rq != isomgr.lt_mf &&
348             !clk_set_rate(isomgr.emc_clk, isomgr.lt_mf * 1000)) {
349
350                 if (isomgr.lt_mf_rq == 0)
351                         clk_enable(isomgr.emc_clk);
352                 isomgr.lt_mf_rq = isomgr.lt_mf;
353                 if (isomgr.lt_mf_rq == 0)
354                         clk_disable(isomgr.emc_clk);
355         }
356
357         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
358                 if (isomgr_clients[i].real_mf != isomgr_clients[i].real_mf_rq &&
359                     !clk_set_rate(isomgr_clients[i].emc_clk,
360                         isomgr_clients[i].real_mf * 1000)) {
361
362                         if (isomgr_clients[i].real_mf_rq == 0)
363                                 clk_enable(isomgr_clients[i].emc_clk);
364                         isomgr_clients[i].real_mf_rq = isomgr_clients[i].real_mf;
365                         if (isomgr_clients[i].real_mf_rq == 0)
366                                 clk_disable(isomgr_clients[i].emc_clk);
367                 }
368         }
369 }
370
371 static void purge_isomgr_client(struct isomgr_client *cp)
372 {
373         cp->magic = 0;
374         atomic_set(&cp->kref.refcount, 0);
375         cp->dedi_bw = 0;
376         cp->rsvd_bw = 0;
377         cp->real_bw = 0;
378         cp->rsvd_mf = 0;
379         cp->real_mf = 0;
380         cp->renegotiate = 0;
381         cp->realize = false;
382         cp->priv = NULL;
383         cp->sleep_bw = 0;
384         cp->margin_bw = 0;
385 }
386
387 static void unregister_iso_client(struct kref *kref)
388 {
389         struct isomgr_client *cp = container_of(kref,
390                                         struct isomgr_client, kref);
391         int client = cp - &isomgr_clients[0];
392
393         trace_tegra_isomgr_unregister_iso_client(cname[client], "enter");
394         isomgr_lock();
395         BUG_ON(cp->realize);
396
397         if (cp->real_bw > cp->margin_bw)
398                 isomgr.avail_bw += cp->real_bw;
399         else
400                 isomgr.avail_bw += cp->margin_bw;
401         isomgr.dedi_bw -= cp->dedi_bw;
402         purge_isomgr_client(cp);
403         update_mc_clock();
404         isomgr_unlock();
405
406         isomgr_scatter(client); /* share the excess */
407         trace_tegra_isomgr_unregister_iso_client(cname[client], "exit");
408 }
409
410 static void isomgr_scatter(int client)
411 {
412         struct isomgr_client *cp;
413         int i;
414
415         trace_tegra_isomgr_scatter(client, 0, cname[client], "enter");
416         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; ++i) {
417                 cp = &isomgr_clients[i];
418                 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
419                         continue;
420                 if (cp->renegotiate && i != client) {
421                         int avail_bw = cp->real_bw + isomgr.avail_bw -
422                                         isomgr.sleep_bw;
423                         if (avail_bw > cp->dedi_bw) {
424                                 trace_tegra_isomgr_scatter(client, 0,
425                                         cname[client], "scatter");
426                                 /* poke flexibles */
427                                 cp->renegotiate(cp->priv, avail_bw);
428                         }
429                 }
430                 kref_put(&cp->kref, unregister_iso_client);
431         }
432         trace_tegra_isomgr_scatter(client, 0, cname[client], "exit");
433 }
434
435 static void isomgr_scavenge(enum tegra_iso_client client)
436 {
437         struct isomgr_client *cp;
438         int i;
439
440         trace_tegra_isomgr_scavenge(client, 0, cname[client], "enter");
441         /* ask flexible clients above dedicated BW levels to pitch in */
442         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; ++i) {
443                 cp = &isomgr_clients[i];
444                 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
445                         continue;
446                 if (cp->renegotiate)
447                         if (cp->real_bw > cp->dedi_bw && i != client &&
448                             !cp->realize) {
449                                 int avail_bw = cp->real_bw + isomgr.avail_bw -
450                                                 isomgr.sleep_bw;
451                                 avail_bw = avail_bw < cp->dedi_bw ?
452                                            cp->dedi_bw : avail_bw;
453                                 trace_tegra_isomgr_scavenge(client, 0,
454                                         cname[client], "renego");
455                                 cp->renegotiate(cp->priv, avail_bw);
456                         }
457                 kref_put(&cp->kref, unregister_iso_client);
458         }
459         trace_tegra_isomgr_scavenge(client, 0, cname[client], "exit");
460 }
461
462 static bool is_client_valid(enum tegra_iso_client client)
463 {
464         if (unlikely(client < 0 || client >= TEGRA_ISO_CLIENT_COUNT ||
465                      !client_valid[client]))
466                 return false;
467         return true;
468 }
469
470 static tegra_isomgr_handle __tegra_isomgr_register(
471                         enum tegra_iso_client client, u32 udedi_bw,
472                         tegra_isomgr_renegotiate renegotiate, void *priv)
473 {
474         s32 dedi_bw = udedi_bw;
475         struct isomgr_client *cp = NULL;
476
477         VALIDATE_CLIENT();
478         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
479                 priv, cname[client], "enter");
480
481         if (unlikely(!udedi_bw && !renegotiate))
482                 goto validation_fail;
483
484         isomgr_lock();
485         cp = &isomgr_clients[client];
486
487         if (unlikely(atomic_read(&cp->kref.refcount)))
488                 goto fail_unlock;
489
490         if (unlikely(dedi_bw > isomgr.max_iso_bw - isomgr.dedi_bw)) {
491 #ifdef CONFIG_TEGRA_ISOMGR_MAX_ISO_BW_QUIRK
492                 int i;
493                 WARN(1, "max_iso_bw is relaxed to %dKB from %dKB",
494                         dedi_bw + isomgr.dedi_bw, isomgr.max_iso_bw);
495                 isomgr.avail_bw += dedi_bw + isomgr.dedi_bw -
496                                    isomgr.max_iso_bw;
497                 isomgr.max_iso_bw = dedi_bw + isomgr.dedi_bw;
498                 pr_info("ISO BW usage:");
499                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
500                         if (!client_valid[i])
501                                 continue;
502                         pr_info("client=%s, iso dedi bw=%dKB",
503                                 cname[i],
504                                 (client == i) ? dedi_bw :
505                                 isomgr_clients[i].dedi_bw);
506                 }
507                 pr_info("revisit BW usage of iso clients");
508 #else
509                 pr_err("iso bandwidth %uKB is not available, client %s\n",
510                         dedi_bw, cname[client]);
511                 goto fail_unlock;
512 #endif
513         }
514
515         purge_isomgr_client(cp);
516         cp->magic = ISOMGR_MAGIC;
517         kref_init(&cp->kref);
518         cp->dedi_bw = dedi_bw;
519         cp->renegotiate = renegotiate;
520         cp->priv = priv;
521         isomgr.dedi_bw += dedi_bw;
522
523         isomgr_unlock();
524         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
525                 priv, cname[client], "exit");
526         return (tegra_isomgr_handle)cp;
527
528 fail_unlock:
529         isomgr_unlock();
530 validation_fail:
531         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
532                 priv, cname[client], "inv_args_exit");
533         return ERR_PTR(-EINVAL);
534 }
535
536 /**
537  * tegra_isomgr_register - register an ISO BW client.
538  *
539  * @client      client to register as an ISO client.
540  * @udedi_bw    minimum bw client can work at. This bw is guarnteed to be
541  *              available for client when ever client need it. Client can
542  *              always request for more bw and client can get it based on
543  *              availability of bw in the system. udedi_bw is specified in KB.
544  * @renegotiate callback function to be called to renegotiate for bw.
545  *              client with no renegotiate callback provided can't allocate
546  *              bw more than udedi_bw.
547  *              Client with renegotiate callback can allocate more than
548  *              udedi_bw and release it during renegotiate callback, when
549  *              other clients in the system need their bw back.
550  *              renegotiate callback is called in two cases. 1. The isomgr
551  *              has excess bw, checking client to see if they need more bw.
552  *              2. The isomgr is out of bw and other clients need their udedi_bw
553  *              back. In this case, the client, which is using higher bw need to
554  *              release the bw and fallback to low(udedi_bw) bw use case.
555  * @priv        pointer to renegotiate callback function.
556  *
557  * @return      returns valid handle on successful registration.
558  * @retval      -EINVAL invalid arguments passed.
559  */
560 tegra_isomgr_handle tegra_isomgr_register(enum tegra_iso_client client,
561                                           u32 udedi_bw,
562                                           tegra_isomgr_renegotiate renegotiate,
563                                           void *priv)
564 {
565         if (test_mode)
566                 return (tegra_isomgr_handle)1;
567         return __tegra_isomgr_register(client, udedi_bw, renegotiate, priv);
568 }
569 EXPORT_SYMBOL(tegra_isomgr_register);
570
571 static void __tegra_isomgr_unregister(tegra_isomgr_handle handle)
572 {
573         struct isomgr_client *cp = (struct isomgr_client *)handle;
574         int client = cp - &isomgr_clients[0];
575
576         VALIDATE_HANDLE();
577         trace_tegra_isomgr_unregister(handle, cname[client]);
578         kref_put(&cp->kref, unregister_iso_client);
579 validation_fail:
580         return;
581 }
582
583 /**
584  * tegra_isomgr_unregister - unregister an ISO BW client.
585  *
586  * @handle      handle acquired during tegra_isomgr_register.
587  */
588 void tegra_isomgr_unregister(tegra_isomgr_handle handle)
589 {
590         if (test_mode)
591                 return;
592         __tegra_isomgr_unregister(handle);
593 }
594 EXPORT_SYMBOL(tegra_isomgr_unregister);
595
596 static u32 __tegra_isomgr_reserve(tegra_isomgr_handle handle,
597                          u32 ubw, u32 ult)
598 {
599         s32 bw = ubw;
600         u32 mf, dvfs_latency = 0;
601         struct isomgr_client *cp = (struct isomgr_client *) handle;
602         int client = cp - &isomgr_clients[0];
603
604         VALIDATE_HANDLE();
605
606         isomgr_lock();
607         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
608                 goto handle_unregistered;
609
610         if (cp->rsvd_bw == ubw && cp->lti == ult) {
611                 kref_put(&cp->kref, unregister_iso_client);
612                 isomgr_unlock();
613                 return cp->lto;
614         }
615
616         trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client], "enter");
617
618         if (unlikely(cp->realize))
619                 goto out;
620
621         if (bw <= cp->margin_bw)
622                 goto skip_bw_check;
623
624         if (unlikely(!cp->renegotiate && bw > cp->dedi_bw))
625                 goto out;
626
627         if (bw > cp->dedi_bw &&
628             bw > isomgr.avail_bw + cp->real_bw - isomgr.sleep_bw)
629                 goto out;
630
631 skip_bw_check:
632         /* Look up MC's min freq that could satisfy requested BW and LT */
633         mf = mc_min_freq(ubw, ult);
634         /* Look up MC's dvfs latency at min freq */
635         dvfs_latency = mc_dvfs_latency(mf);
636
637         cp->lti = ult;          /* remember client spec'd LT (usec) */
638         cp->lto = dvfs_latency; /* remember MC calculated LT (usec) */
639         cp->rsvd_mf = mf;       /* remember associated min freq */
640         cp->rsvd_bw = bw;
641 out:
642         kref_put(&cp->kref, unregister_iso_client);
643         isomgr_unlock();
644         trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client],
645                 dvfs_latency ? "exit" : "rsrv_fail_exit");
646         return dvfs_latency;
647 handle_unregistered:
648         isomgr_unlock();
649         trace_tegra_isomgr_reserve(handle, ubw, ult,
650                 cname[client], "inv_handle_exit");
651         return dvfs_latency;
652 validation_fail:
653         trace_tegra_isomgr_reserve(handle, ubw, ult, "unk", "inv_handle_exit");
654         return dvfs_latency;
655 }
656
657 /**
658  * tegra_isomgr_reserve - reserve bw for the ISO client.
659  *
660  * @handle      handle acquired during tegra_isomgr_register.
661  * @ubw         bandwidth in KBps.
662  * @ult         latency that can be tolerated by client in usec.
663  *
664  * returns dvfs latency thresh in usec.
665  * return 0 indicates that reserve failed.
666  */
667 u32 tegra_isomgr_reserve(tegra_isomgr_handle handle,
668                          u32 ubw, u32 ult)
669 {
670         if (test_mode)
671                 return 1;
672         return __tegra_isomgr_reserve(handle, ubw, ult);
673 }
674 EXPORT_SYMBOL(tegra_isomgr_reserve);
675
676 static u32 __tegra_isomgr_realize(tegra_isomgr_handle handle)
677 {
678         bool retry = false;
679         u32 dvfs_latency = 0;
680         s32 delta_bw = 0;
681         struct isomgr_client *cp = (struct isomgr_client *) handle;
682         int client = cp - &isomgr_clients[0];
683
684         VALIDATE_HANDLE();
685
686 retry:
687         isomgr_lock();
688         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
689                 goto handle_unregistered;
690
691         if (cp->rsvd_bw == cp->real_bw && cp->rsvd_mf == cp->real_mf) {
692                 kref_put(&cp->kref, unregister_iso_client);
693                 isomgr_unlock();
694                 return cp->lto;
695         }
696
697         if (!retry)
698                 trace_tegra_isomgr_realize(handle, cname[client], "enter");
699         if (cp->margin_bw < cp->real_bw)
700                 isomgr.avail_bw += cp->real_bw - cp->margin_bw;
701         cp->real_bw = 0;
702         cp->realize = true;
703         BUG_ON(isomgr.avail_bw > isomgr.max_iso_bw);
704
705         if (cp->rsvd_bw <= cp->margin_bw) {
706                 BUG_ON(cp->sleep_bw);
707                 cp->real_bw = cp->rsvd_bw; /* reservation has been realized */
708                 cp->real_mf = cp->rsvd_mf; /* minimum frequency realized */
709         } else if (cp->rsvd_bw <= isomgr.avail_bw + cp->margin_bw) {
710                 delta_bw = cp->rsvd_bw - cp->margin_bw;
711                 isomgr.avail_bw -= delta_bw;
712                 cp->real_bw = cp->rsvd_bw; /* reservation has been realized */
713                 cp->real_mf = cp->rsvd_mf; /* minimum frequency realized */
714                 if (cp->sleep_bw) {
715                         isomgr.sleep_bw -= delta_bw;
716                         cp->sleep_bw -= delta_bw;
717                         BUG_ON(cp->sleep_bw);
718                 }
719                 BUG_ON(isomgr.avail_bw < 0);
720                 SANITY_CHECK_AVAIL_BW();
721         } else {
722                 /* Protection from first scavenge failure */
723                 if (!cp->sleep_bw) {
724                         delta_bw = cp->rsvd_bw - cp->margin_bw;
725                         SANITY_CHECK_AVAIL_BW();
726                         isomgr.sleep_bw += delta_bw;
727                         BUG_ON(cp->sleep_bw);
728                         cp->sleep_bw += delta_bw;
729                 }
730                 kref_put(&cp->kref, unregister_iso_client);
731                 isomgr_unlock();
732                 isomgr_scavenge(client);
733                 retry = true;
734                 goto retry;
735         }
736
737         dvfs_latency = (u32)cp->lto;
738         cp->realize = false;
739         update_mc_clock();
740
741         kref_put(&cp->kref, unregister_iso_client);
742         isomgr_unlock();
743         trace_tegra_isomgr_realize(handle, cname[client],
744                 dvfs_latency ? "exit" : "real_fail_exit");
745         return dvfs_latency;
746 handle_unregistered:
747         isomgr_unlock();
748         trace_tegra_isomgr_realize(handle, cname[client], "inv_handle_exit");
749         return dvfs_latency;
750 validation_fail:
751         trace_tegra_isomgr_realize(handle, "unk", "inv_handle_exit");
752         return dvfs_latency;
753 }
754
755 /**
756  * tegra_isomgr_realize - realize the bw reserved by client.
757  *
758  * @handle      handle acquired during tegra_isomgr_register.
759  *
760  * returns dvfs latency thresh in usec.
761  * return 0 indicates that realize failed.
762  */
763 u32 tegra_isomgr_realize(tegra_isomgr_handle handle)
764 {
765         if (test_mode)
766                 return 1;
767         return __tegra_isomgr_realize(handle);
768 }
769 EXPORT_SYMBOL(tegra_isomgr_realize);
770
771 static int __tegra_isomgr_set_margin(enum tegra_iso_client client,
772                                         u32 bw, bool wait)
773 {
774         int ret = -EINVAL;
775         s32 high_bw;
776         struct isomgr_client *cp = NULL;
777
778         trace_tegra_isomgr_set_margin(client, bw, wait, "enter");
779         VALIDATE_CLIENT();
780
781 retry:
782         isomgr_lock();
783         cp = &isomgr_clients[client];
784         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
785                 goto handle_unregistered;
786
787         if (bw > cp->dedi_bw)
788                 goto out;
789
790         if (bw <= cp->real_bw) {
791                 if (cp->margin_bw > cp->real_bw)
792                         isomgr.avail_bw += cp->margin_bw - cp->real_bw;
793                 cp->margin_bw = bw;
794         } else if (bw <= cp->margin_bw) {
795                 BUG_ON(cp->margin_bw > cp->real_bw);
796                 isomgr.avail_bw += cp->margin_bw - bw;
797                 cp->margin_bw = bw;
798                 BUG_ON(cp->margin_bw > cp->real_bw);
799         } else if (bw > cp->margin_bw) {
800                 high_bw = (cp->margin_bw > cp->real_bw) ?
801                                 cp->margin_bw : cp->real_bw;
802                 if (bw - high_bw <= isomgr.avail_bw - isomgr.sleep_bw) {
803                         isomgr.avail_bw -= bw - high_bw;
804                         cp->margin_bw = bw;
805                 } else {
806                         if (wait) {
807                                 kref_put(&cp->kref, unregister_iso_client);
808                                 isomgr_unlock();
809                                 wait = false;
810                                 isomgr_scavenge(client);
811                                 goto retry;
812                         }
813                         ret = -ENOMEM;
814                         goto out;
815                 }
816         }
817         ret = 0;
818 out:
819         kref_put(&cp->kref, unregister_iso_client);
820         isomgr_unlock();
821         trace_tegra_isomgr_set_margin(client, bw, wait,
822                                         ret ? "fail_exit" : "exit");
823         return ret;
824 handle_unregistered:
825         isomgr_unlock();
826 validation_fail:
827         trace_tegra_isomgr_set_margin(client, bw, wait, "inv_arg_fail");
828         return ret;
829 }
830
831 /**
832  * This sets bw aside for the client specified.
833  * This bw can never be used for other clients needs.
834  * margin bw, if not zero, should always be greater than equal to
835  * reserved/realized bw.
836  *
837  * @client client
838  * @bw bw margin KB.
839  * @wait if true and bw is not available, it would wait till bw is available.
840  *        if false, it would return immediately with success or failure.
841  *
842  * @retval  0 operation is successful.
843  * @retval -ENOMEM Iso Bw requested is not avialable.
844  * @retval -EINVAL Invalid arguments, bw is less than reserved/realized bw.
845  */
846 int tegra_isomgr_set_margin(enum tegra_iso_client client, u32 bw, bool wait)
847 {
848         if (test_mode)
849                 return 0;
850         return __tegra_isomgr_set_margin(client, bw, wait);
851 }
852 EXPORT_SYMBOL(tegra_isomgr_set_margin);
853
854 static int __tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
855 {
856         int ret = -EINVAL;
857
858         if (unlikely(!is_client_valid(client)))
859                 return ret;
860
861         /* FIXME: get this from renegotiable clients(display driver). */
862         ret = 100;
863         if (isomgr.avail_bw >= bw)
864                 ret = 0;
865         trace_tegra_isomgr_get_imp_time(client, bw, ret, cname[client]);
866         return ret;
867 }
868
869 /**
870  * Returns the imp time required to realize the bw request.
871  * The time returned is an approximate. It is possible that imp
872  * time is returned as zero and still realize would be blocked for
873  * non-zero time in realize call.
874  *
875  * @client      client id
876  * @bw          bw in KB/sec
877  *
878  * @returns     time in milliseconds.
879  * @retval      -EINVAL, client id is invalid.
880  */
881 int tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
882 {
883         if (test_mode)
884                 return 0;
885         return __tegra_isomgr_get_imp_time(client, bw);
886 }
887 EXPORT_SYMBOL(tegra_isomgr_get_imp_time);
888
889 static u32 __tegra_isomgr_get_available_iso_bw(void)
890 {
891         trace_tegra_isomgr_get_available_iso_bw(isomgr.avail_bw);
892         return isomgr.avail_bw;
893 }
894
895 /**
896  * Returns available iso bw at the time of calling this API.
897  *
898  * @returns     available bw in KB/sec.
899  */
900 u32 tegra_isomgr_get_available_iso_bw(void)
901 {
902         if (test_mode)
903                 return UINT_MAX;
904         return __tegra_isomgr_get_available_iso_bw();
905 }
906 EXPORT_SYMBOL(tegra_isomgr_get_available_iso_bw);
907
908 static u32 __tegra_isomgr_get_total_iso_bw(void)
909 {
910         trace_tegra_isomgr_get_total_iso_bw(isomgr.max_iso_bw);
911         return isomgr.max_iso_bw;
912 }
913
914 /**
915  * Returns total iso bw in the system.
916  *
917  * @returns     total bw in KB/sec.
918  */
919 u32 tegra_isomgr_get_total_iso_bw(void)
920 {
921         if (test_mode)
922                 return UINT_MAX;
923         return __tegra_isomgr_get_total_iso_bw();
924 }
925 EXPORT_SYMBOL(tegra_isomgr_get_total_iso_bw);
926
927 #ifdef CONFIG_TEGRA_ISOMGR_SYSFS
928 static ssize_t isomgr_show(struct kobject *kobj,
929         struct kobj_attribute *attr, char *buf);
930
931 static const struct kobj_attribute lt_mf_attr =
932         __ATTR(lt_mf, 0444, isomgr_show, 0);
933 static const struct kobj_attribute avail_bw_attr =
934         __ATTR(avail_bw, 0444, isomgr_show, 0);
935 static const struct kobj_attribute max_iso_bw_attr =
936         __ATTR(max_iso_bw, 0444, isomgr_show, 0);
937 static const struct kobj_attribute version_attr =
938         __ATTR(version, 0444, isomgr_show, 0);
939
940 static const struct attribute *isomgr_attrs[] = {
941         &lt_mf_attr.attr,
942         &avail_bw_attr.attr,
943         &max_iso_bw_attr.attr,
944         &version_attr.attr,
945         NULL
946 };
947
948 static ssize_t isomgr_show(struct kobject *kobj,
949         struct kobj_attribute *attr, char *buf)
950 {
951         ssize_t rval = 0;
952
953         if (attr == &lt_mf_attr)
954                 rval = sprintf(buf, "%dKHz\n", isomgr.lt_mf);
955         else if (attr == &avail_bw_attr)
956                 rval = sprintf(buf, "%dKB\n", isomgr.avail_bw);
957         else if (attr == &max_iso_bw_attr)
958                 rval = sprintf(buf, "%dKB\n", isomgr.max_iso_bw);
959         else if (attr == &version_attr)
960                 rval = sprintf(buf, "%d\n", ISOMGR_SYSFS_VERSION);
961         return rval;
962 }
963
964 static ssize_t isomgr_client_show(struct kobject *kobj,
965         struct kobj_attribute *attr, char *buf)
966 {
967         int client = ((char *)attr - (char *)isomgr_clients) /
968                         sizeof(struct isomgr_client);
969         struct isomgr_client *cp =
970                         (struct isomgr_client *)&isomgr_clients[client];
971         ssize_t rval = 0;
972
973         if (attr == &cp->client_attrs.dedi_bw)
974                 rval = sprintf(buf, "%dKB\n", cp->dedi_bw);
975         else if (attr == &cp->client_attrs.rsvd_bw)
976                 rval = sprintf(buf, "%dKB\n", cp->rsvd_bw);
977         else if (attr == &cp->client_attrs.real_bw)
978                 rval = sprintf(buf, "%dKB\n", cp->real_bw);
979         else if (attr == &cp->client_attrs.lti)
980                 rval = sprintf(buf, "%dus\n", cp->lti);
981         else if (attr == &cp->client_attrs.lto)
982                 rval = sprintf(buf, "%dus\n", cp->lto);
983         else if (attr == &cp->client_attrs.rsvd_mf)
984                 rval = sprintf(buf, "%dKHz\n", cp->rsvd_mf);
985         else if (attr == &cp->client_attrs.real_mf)
986                 rval = sprintf(buf, "%dKHz\n", cp->real_mf);
987         else if (attr == &cp->client_attrs.sleep_bw)
988                 rval = sprintf(buf, "%dKB\n", cp->sleep_bw);
989         else if (attr == &cp->client_attrs.margin_bw)
990                 rval = sprintf(buf, "%dKB\n", cp->margin_bw);
991         return rval;
992 }
993
994 static const struct isomgr_client_attrs client_attrs = {
995         __ATTR(dedi_bw, 0444, isomgr_client_show, 0),
996         __ATTR(rsvd_bw, 0444, isomgr_client_show, 0),
997         __ATTR(real_bw, 0444, isomgr_client_show, 0),
998         __ATTR(lti,     0444, isomgr_client_show, 0),
999         __ATTR(lto,     0444, isomgr_client_show, 0),
1000         __ATTR(rsvd_mf, 0444, isomgr_client_show, 0),
1001         __ATTR(real_mf, 0444, isomgr_client_show, 0),
1002         __ATTR(sleep_bw, 0444, isomgr_client_show, 0),
1003         __ATTR(margin_bw, 0444, isomgr_client_show, 0),
1004 };
1005
1006 #define NCATTRS (sizeof(client_attrs) / sizeof(struct kobj_attribute))
1007 static const struct attribute *client_attr_list[][NCATTRS+1] = {
1008 #define CLIENT_ATTR(i)\
1009         {\
1010                 &isomgr_clients[i].client_attrs.dedi_bw.attr,\
1011                 &isomgr_clients[i].client_attrs.rsvd_bw.attr,\
1012                 &isomgr_clients[i].client_attrs.real_bw.attr,\
1013                 &isomgr_clients[i].client_attrs.lti.attr,\
1014                 &isomgr_clients[i].client_attrs.lto.attr,\
1015                 &isomgr_clients[i].client_attrs.rsvd_mf.attr,\
1016                 &isomgr_clients[i].client_attrs.real_mf.attr,\
1017                 &isomgr_clients[i].client_attrs.sleep_bw.attr,\
1018                 &isomgr_clients[i].client_attrs.margin_bw.attr,\
1019                 NULL\
1020         },
1021         CLIENT_ATTR(0)
1022         CLIENT_ATTR(1)
1023         CLIENT_ATTR(2)
1024         CLIENT_ATTR(3)
1025         CLIENT_ATTR(4)
1026         CLIENT_ATTR(5)
1027         CLIENT_ATTR(6)
1028 };
1029
1030 static void isomgr_create_client(int client, const char *name)
1031 {
1032         struct isomgr_client *cp = &isomgr_clients[client];
1033
1034         /* If this error hits, more CLIENT_ATTR(x) need to be added
1035          * in the above array client_attr_list.
1036          */
1037         BUILD_BUG_ON(TEGRA_ISO_CLIENT_COUNT > 7);
1038         BUG_ON(!isomgr.kobj);
1039         BUG_ON(cp->client_kobj);
1040         cp->client_kobj = kobject_create_and_add(name, isomgr.kobj);
1041         if (!cp->client_kobj) {
1042                 pr_err("failed to create sysfs client dir");
1043                 return;
1044         }
1045         cp->client_attrs = client_attrs;
1046         if (sysfs_create_files(cp->client_kobj, &client_attr_list[client][0])) {
1047                 pr_err("failed to create sysfs client files");
1048                 kobject_del(cp->client_kobj);
1049                 return;
1050         }
1051 }
1052
1053 static void isomgr_create_sysfs(void)
1054 {
1055         int i;
1056
1057         BUG_ON(isomgr.kobj);
1058         isomgr.kobj = kobject_create_and_add("isomgr", kernel_kobj);
1059         if (!isomgr.kobj) {
1060                 pr_err("failed to create kobject");
1061                 return;
1062         }
1063         if (sysfs_create_files(isomgr.kobj, isomgr_attrs)) {
1064                 pr_err("failed to create sysfs files");
1065                 kobject_del(isomgr.kobj);
1066                 isomgr.kobj = 0;
1067                 return;
1068         }
1069
1070         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
1071                 if (client_valid[i])
1072                         isomgr_create_client(isoclient_info[i].client,
1073                                              isoclient_info[i].name);
1074         }
1075 }
1076 #else
1077 static inline void isomgr_create_sysfs(void) {};
1078 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
1079
1080 int __init isomgr_init(void)
1081 {
1082         int i;
1083         unsigned int max_emc_clk;
1084         unsigned int max_emc_bw;
1085
1086         mutex_init(&isomgr.lock);
1087         isoclient_info = get_iso_client_info();
1088
1089         for (i = 0; ; i++) {
1090                 if (isoclient_info[i].name)
1091                         client_valid[isoclient_info[i].client] = true;
1092                 else
1093                         break;
1094         }
1095
1096         isomgr.emc_clk = clk_get_sys("iso", "emc");
1097         if (IS_ERR_OR_NULL(isomgr.emc_clk)) {
1098                 pr_err("couldn't find iso emc clock. disabling isomgr.");
1099                 test_mode = 1;
1100                 return 0;
1101         }
1102
1103         if (!isomgr.max_iso_bw) {
1104                 max_emc_clk = clk_round_rate(isomgr.emc_clk, ULONG_MAX) / 1000;
1105                 pr_info("iso emc max clk=%dKHz", max_emc_clk);
1106                 max_emc_bw = tegra_emc_freq_req_to_bw(max_emc_clk);
1107                 /* ISO clients can use iso_bw_percentage of max emc bw. */
1108                 isomgr.max_iso_bw = max_emc_bw * iso_bw_percentage / 100;
1109                 pr_info("max_iso_bw=%dKB", isomgr.max_iso_bw);
1110                 isomgr.avail_bw = isomgr.max_iso_bw;
1111         }
1112
1113         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
1114                 atomic_set(&isomgr_clients[i].kref.refcount, 0);
1115                 init_completion(&isomgr_clients[i].cmpl);
1116                 if (client_valid[i]) {
1117                         isomgr_clients[i].emc_clk = clk_get_sys(
1118                                         isoclient_info[i].dev_name,
1119                                         isoclient_info[i].emc_clk_name);
1120                         if (IS_ERR_OR_NULL(isomgr_clients[i].emc_clk)) {
1121                                 pr_err("couldn't find %s %s clock",
1122                                         isoclient_info[i].dev_name,
1123                                         isoclient_info[i].emc_clk_name);
1124                                 pr_err("disabling iso mgr");
1125                                 test_mode = 1;
1126                                 return 0;
1127                         }
1128                 }
1129         }
1130         isomgr_create_sysfs();
1131         return 0;
1132 }
1133
1134 int tegra_isomgr_enable_test_mode(void)
1135 {
1136         int i;
1137         struct isomgr_client *cp = NULL;
1138
1139         isomgr_lock();
1140         test_mode = 1;
1141         isomgr_unlock();
1142         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
1143                 if (!client_valid[i])
1144                         continue;
1145                 cp = &isomgr_clients[i];
1146 retry:
1147                 __tegra_isomgr_unregister(cp);
1148                 if (atomic_read(&cp->kref.refcount))
1149                         goto retry;
1150         }
1151         pr_info("done");
1152         return 0;
1153 }
1154 EXPORT_SYMBOL(tegra_isomgr_enable_test_mode);
1155
1156 tegra_isomgr_handle test_tegra_isomgr_register(enum tegra_iso_client client,
1157                                           u32 dedicated_bw,     /* KB/sec */
1158                                           tegra_isomgr_renegotiate renegotiate,
1159                                           void *priv)
1160 {
1161         return __tegra_isomgr_register(client, dedicated_bw, renegotiate, priv);
1162 }
1163 EXPORT_SYMBOL(test_tegra_isomgr_register);
1164
1165 void test_tegra_isomgr_unregister(tegra_isomgr_handle handle)
1166 {
1167         return __tegra_isomgr_unregister(handle);
1168 }
1169 EXPORT_SYMBOL(test_tegra_isomgr_unregister);
1170
1171 u32 test_tegra_isomgr_reserve(tegra_isomgr_handle handle,
1172                          u32 bw,        /* KB/sec */
1173                          u32 lt)        /* usec */
1174 {
1175         return __tegra_isomgr_reserve(handle, bw, lt);
1176 }
1177 EXPORT_SYMBOL(test_tegra_isomgr_reserve);
1178
1179 u32 test_tegra_isomgr_realize(tegra_isomgr_handle handle)
1180 {
1181         return __tegra_isomgr_realize(handle);
1182 }
1183 EXPORT_SYMBOL(test_tegra_isomgr_realize);
1184
1185 int test_tegra_isomgr_set_margin(enum tegra_iso_client client,
1186                                 u32 bw, bool wait)
1187 {
1188         return __tegra_isomgr_set_margin(client, bw, wait);
1189 }
1190 EXPORT_SYMBOL(test_tegra_isomgr_set_margin);
1191
1192 int test_tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1193 {
1194         return __tegra_isomgr_get_imp_time(client, bw);
1195 }
1196 EXPORT_SYMBOL(test_tegra_isomgr_get_imp_time);
1197
1198 u32 test_tegra_isomgr_get_available_iso_bw(void)
1199 {
1200         return __tegra_isomgr_get_available_iso_bw();
1201 }
1202 EXPORT_SYMBOL(test_tegra_isomgr_get_available_iso_bw);
1203
1204 u32 test_tegra_isomgr_get_total_iso_bw(void)
1205 {
1206         return __tegra_isomgr_get_total_iso_bw();
1207 }
1208 EXPORT_SYMBOL(test_tegra_isomgr_get_total_iso_bw);