]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - drivers/platform/tegra/mc/isomgr.c
df102cd8c03571befefabe8285d985451eb2876f
[hercules2020/nv-tegra/linux-4.4.git] / drivers / platform / tegra / mc / isomgr.c
1 /*
2  * arch/arm/mach-tegra/isomgr.c
3  *
4  * Copyright (c) 2012-2016, 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(): " fmt, __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/err.h>
34 #include <linux/kref.h>
35 #include <linux/sched.h>
36 #include <linux/tegra-soc.h>
37 #include <asm/processor.h>
38 #include <asm/current.h>
39
40 #include <linux/platform/tegra/isomgr.h>
41
42 #include <linux/platform/tegra/emc_bwmgr.h>
43 #ifdef CONFIG_COMMON_CLK
44 #include <linux/platform/tegra/bwmgr_mc.h>
45 #else
46 #include <linux/platform/tegra/mc.h>
47 #include <linux/clk.h>
48 #include <linux/platform/tegra/clock.h>
49 #endif
50
51 #define CREATE_TRACE_POINTS
52 #include <trace/events/isomgr.h>
53
54 #define ISOMGR_SYSFS_VERSION 0  /* increment on change */
55 #define ISOMGR_DEBUG 1
56
57 #if ISOMGR_DEBUG
58 #define SANITY_CHECK_AVAIL_BW() { \
59         int t = 0; \
60         int idx = 0; \
61         for (idx = 0; idx < TEGRA_ISO_CLIENT_COUNT; idx++) { \
62                 if (isomgr_clients[idx].real_bw >= \
63                     isomgr_clients[idx].margin_bw) \
64                         t += isomgr_clients[idx].real_bw; \
65                 else \
66                         t += isomgr_clients[idx].margin_bw; \
67         } \
68         if (t + isomgr.avail_bw != isomgr.max_iso_bw) { \
69                 pr_err("bw mismatch, line=%d\n", __LINE__); \
70                 pr_err("t+isomgr.avail_bw=%d, isomgr.max_iso_bw=%d\n", \
71                         t + isomgr.avail_bw, isomgr.max_iso_bw); \
72                 BUG(); \
73         } \
74 }
75 #else
76 #define SANITY_CHECK_AVAIL_BW()
77 #endif
78
79 #define VALIDATE_HANDLE() \
80 do { \
81         if (unlikely(!cp || !is_client_valid(client) || \
82                      cp->magic != ISOMGR_MAGIC)) { \
83                 pr_err("bad handle %p\n", handle); \
84                 goto validation_fail; \
85         } \
86 } while (0)
87
88 #define VALIDATE_CLIENT() \
89 do { \
90         if (unlikely(!is_client_valid(client))) { \
91                 pr_err("invalid client %d\n", client); \
92                 goto validation_fail; \
93         } \
94 } while (0)
95
96 /* To allow test code take over control */
97 static bool test_mode;
98
99 static char *cname[] = {
100         "disp_0",
101         "disp_1",
102         "disp_2",
103         "vi_0",
104         "vi_1",
105         "isp_a",
106         "isp_b",
107         "bbc_0",
108         "tegra_camera_ctrl",
109         "ape_adma",
110         "eqos",
111         "unknown"
112 };
113
114 struct isoclient_info {
115         enum tegra_iso_client client;
116         char *name;
117         char *dev_name;
118         char *emc_clk_name;
119         enum tegra_bwmgr_client_id bwmgr_id;
120 };
121
122 static struct isoclient_info *isoclient_info;
123 static int isoclients;
124 static bool client_valid[TEGRA_ISO_CLIENT_COUNT];
125 static int iso_bw_percentage = 100;
126
127 static struct isoclient_info tegra_null_isoclients[] = {
128         /* This must be last entry*/
129         {
130                 .client = TEGRA_ISO_CLIENT_COUNT,
131                 .name = NULL,
132         },
133 };
134
135 static struct isoclient_info tegra11x_isoclients[] = {
136         {
137                 .client = TEGRA_ISO_CLIENT_DISP_0,
138                 .name = "disp_0",
139                 .dev_name = "tegradc.0",
140                 .emc_clk_name = "emc",
141         },
142         {
143                 .client = TEGRA_ISO_CLIENT_DISP_1,
144                 .name = "disp_1",
145                 .dev_name = "tegradc.1",
146                 .emc_clk_name = "emc",
147         },
148         {
149                 .client = TEGRA_ISO_CLIENT_VI_0,
150                 .name = "vi_0",
151                 .dev_name = "vi",
152                 .emc_clk_name = "emc",
153         },
154         /* This must be last entry*/
155         {
156                 .client = TEGRA_ISO_CLIENT_COUNT,
157                 .name = NULL,
158         },
159 };
160
161 static struct isoclient_info tegra14x_isoclients[] = {
162         {
163                 .client = TEGRA_ISO_CLIENT_DISP_0,
164                 .name = "disp_0",
165                 .dev_name = "tegradc.0",
166                 .emc_clk_name = "emc",
167         },
168         {
169                 .client = TEGRA_ISO_CLIENT_DISP_1,
170                 .name = "disp_1",
171                 .dev_name = "tegradc.1",
172                 .emc_clk_name = "emc",
173         },
174         {
175                 .client = TEGRA_ISO_CLIENT_VI_0,
176                 .name = "vi_0",
177                 .dev_name = "vi",
178                 .emc_clk_name = "emc",
179         },
180         {
181                 .client = TEGRA_ISO_CLIENT_BBC_0,
182                 .name = "bbc_0",
183                 .dev_name = "tegra_bb.0",
184                 .emc_clk_name = "emc_bw",
185         },
186         /* This must be last entry*/
187         {
188                 .client = TEGRA_ISO_CLIENT_COUNT,
189                 .name = NULL,
190         },
191 };
192
193 static struct isoclient_info tegra12x_isoclients[] = {
194         {
195                 .client = TEGRA_ISO_CLIENT_DISP_0,
196                 .name = "disp_0",
197                 .dev_name = "tegradc.0",
198                 .emc_clk_name = "emc",
199         },
200         {
201                 .client = TEGRA_ISO_CLIENT_DISP_1,
202                 .name = "disp_1",
203                 .dev_name = "tegradc.1",
204                 .emc_clk_name = "emc",
205         },
206         {
207                 .client = TEGRA_ISO_CLIENT_VI_0,
208                 .name = "vi_0",
209                 .dev_name = "tegra_vi",
210                 .emc_clk_name = "emc",
211         },
212         {
213                 .client = TEGRA_ISO_CLIENT_ISP_A,
214                 .name = "isp_a",
215                 .dev_name = "tegra_isp.0",
216                 .emc_clk_name = "emc",
217         },
218         {
219                 .client = TEGRA_ISO_CLIENT_ISP_B,
220                 .name = "isp_b",
221                 .dev_name = "tegra_isp.1",
222                 .emc_clk_name = "emc",
223         },
224         {
225                 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
226                 .name = "tegra_camera",
227                 .dev_name = "tegra_camera_ctrl",
228                 .emc_clk_name = "iso.emc",
229         },
230         /* This must be last entry*/
231         {
232                 .client = TEGRA_ISO_CLIENT_COUNT,
233                 .name = NULL,
234         },
235 };
236
237 static struct isoclient_info tegra21x_isoclients[] = {
238         {
239                 .client = TEGRA_ISO_CLIENT_DISP_0,
240                 .name = "disp_0",
241                 .dev_name = "tegradc.0",
242                 .emc_clk_name = "emc",
243         },
244         {
245                 .client = TEGRA_ISO_CLIENT_DISP_1,
246                 .name = "disp_1",
247                 .dev_name = "tegradc.1",
248                 .emc_clk_name = "emc",
249         },
250         {
251                 .client = TEGRA_ISO_CLIENT_VI_0,
252                 .name = "vi_0",
253                 .dev_name = "tegra_vi",
254                 .emc_clk_name = "emc",
255         },
256         {
257                 .client = TEGRA_ISO_CLIENT_ISP_A,
258                 .name = "isp_a",
259                 .dev_name = "tegra_isp.0",
260                 .emc_clk_name = "emc",
261         },
262         {
263                 .client = TEGRA_ISO_CLIENT_ISP_B,
264                 .name = "isp_b",
265                 .dev_name = "tegra_isp.1",
266                 .emc_clk_name = "emc",
267         },
268         {
269                 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
270                 .name = "tegra_camera",
271                 .dev_name = "tegra_camera_ctrl",
272                 .emc_clk_name = "iso.emc",
273         },
274         /* This must be last entry*/
275         {
276                 .client = TEGRA_ISO_CLIENT_COUNT,
277                 .name = NULL,
278         },
279 };
280
281 static struct isoclient_info tegra18x_isoclients[] = {
282         {
283                 .client = TEGRA_ISO_CLIENT_DISP_0,
284                 .name = "disp_0",
285                 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP0,
286         },
287         {
288                 .client = TEGRA_ISO_CLIENT_DISP_1,
289                 .name = "disp_1",
290                 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP1,
291         },
292         {
293                 .client = TEGRA_ISO_CLIENT_DISP_2,
294                 .name = "disp_2",
295                 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP2,
296         },
297         {
298                 .client = TEGRA_ISO_CLIENT_VI_0,
299                 .name = "vi_0",
300                 .bwmgr_id = TEGRA_BWMGR_CLIENT_VI,
301         },
302         {
303                 .client = TEGRA_ISO_CLIENT_ISP_A,
304                 .name = "isp_a",
305                 .bwmgr_id = TEGRA_BWMGR_CLIENT_ISPA,
306         },
307         {
308                 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
309                 .name = "camera",
310                 .bwmgr_id = TEGRA_BWMGR_CLIENT_CAMERA,
311         },
312         {
313                 .client = TEGRA_ISO_CLIENT_APE_ADMA,
314                 .name = "ape_adma",
315                 .bwmgr_id = TEGRA_BWMGR_CLIENT_APE_ADMA,
316         },
317         {
318                 .client = TEGRA_ISO_CLIENT_EQOS,
319                 .name = "eqos",
320                 .bwmgr_id = TEGRA_BWMGR_CLIENT_EQOS,
321         },
322         /* This must be last entry*/
323         {
324                 .client = TEGRA_ISO_CLIENT_COUNT,
325                 .name = NULL,
326         },
327 };
328
329 static void isomgr_scatter(int client);
330
331
332 #define ISOMGR_MAGIC  0x150A1C
333 static struct isomgr_client {
334         u32 magic;              /* magic to identify handle */
335         struct kref kref;       /* ref counting */
336         s32 dedi_bw;            /* BW dedicated to this client  (KB/sec) */
337         s32 rsvd_bw;            /* BW reserved for this client  (KB/sec) */
338         s32 real_bw;            /* BW realized for this client  (KB/sec) */
339         s32 lti;                /* Client spec'd Latency Tolerance (usec) */
340         s32 lto;                /* MC calculated Latency Tolerance (usec) */
341         s32 rsvd_mf;            /* reserved minimum freq in support of LT */
342         s32 real_mf;            /* realized minimum freq in support of LT */
343         s32 real_mf_rq;         /* real_mf requested */
344         tegra_isomgr_renegotiate renegotiate;   /* ask client to renegotiate */
345         bool realize;           /* bw realization in progress */
346         s32 sleep_bw;           /* sleeping for realize */
347         s32 margin_bw;          /* BW set aside for this client (KB/sec) */
348         u8 limit_bw_percentage; /* Insufficient HW buffers cause BW to be
349                                  * limited to this percentage of DRAM BW
350                                  */
351         void *priv;             /* client driver's private data */
352         struct completion cmpl; /* so we can sleep waiting for delta BW */
353
354 #ifdef CONFIG_COMMON_CLK
355         struct tegra_bwmgr_client *bwmgr_handle;
356 #else
357         struct clk *emc_clk;    /* client emc clk for bw */
358 #endif
359
360 #ifdef CONFIG_TEGRA_ISOMGR_SYSFS
361         struct kobject *client_kobj;
362         struct isomgr_client_attrs {
363                 struct kobj_attribute dedi_bw;
364                 struct kobj_attribute rsvd_bw;
365                 struct kobj_attribute real_bw;
366                 struct kobj_attribute lti;
367                 struct kobj_attribute lto;
368                 struct kobj_attribute rsvd_mf;
369                 struct kobj_attribute real_mf;
370                 struct kobj_attribute sleep_bw;
371                 struct kobj_attribute margin_bw;
372         } client_attrs;
373 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
374 } isomgr_clients[TEGRA_ISO_CLIENT_COUNT];
375
376 static struct {
377         struct mutex lock;              /* to lock ALL isomgr state */
378         struct task_struct *task;       /* check reentrant/mismatched locks */
379
380 #ifdef CONFIG_COMMON_CLK
381         struct tegra_bwmgr_client *bwmgr_handle;
382 #else
383         struct clk *emc_clk;            /* isomgr emc clock for floor freq */
384 #endif
385
386         s32 lt_mf;                      /* min freq to support worst LT */
387         s32 lt_mf_rq;                   /* requested lt_mf */
388         s32 avail_bw;                   /* globally available MC BW */
389         s32 dedi_bw;                    /* total BW 'dedicated' to clients */
390         s32 sleep_bw;                   /* pending bw requirement */
391         u32 max_iso_bw;                 /* max ISO BW MC can accomodate */
392         struct kobject *kobj;           /* for sysfs linkage */
393 } isomgr = {
394         .max_iso_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
395         .avail_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
396 };
397
398 static struct isoclient_info *get_iso_client_info(int *length)
399 {
400         enum tegra_chipid cid;
401         struct isoclient_info *cinfo;
402         int i, len;
403
404         cid = tegra_get_chipid();
405         switch (cid) {
406         case TEGRA_CHIPID_TEGRA11:
407                 cinfo = tegra11x_isoclients;
408                 len = ARRAY_SIZE(tegra11x_isoclients);
409                 iso_bw_percentage = 50;
410                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
411                         isomgr_clients[i].limit_bw_percentage = 100;
412                 break;
413         case TEGRA_CHIPID_TEGRA14:
414                 cinfo = tegra14x_isoclients;
415                 len = ARRAY_SIZE(tegra14x_isoclients);
416                 iso_bw_percentage = 50;
417                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
418                         isomgr_clients[i].limit_bw_percentage = 100;
419                 break;
420         case TEGRA_CHIPID_TEGRA12:
421         case TEGRA_CHIPID_TEGRA13:
422                 cinfo = tegra12x_isoclients;
423                 len = ARRAY_SIZE(tegra12x_isoclients);
424                 iso_bw_percentage = 50;
425                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
426                         isomgr_clients[i].limit_bw_percentage = 100;
427                 break;
428         case TEGRA_CHIPID_TEGRA21:
429                 cinfo = tegra21x_isoclients;
430                 iso_bw_percentage = 45; /* Hack: Should be determined based on
431                                          * DRAM type
432                                          */
433                 len = ARRAY_SIZE(tegra21x_isoclients);
434                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
435                         isomgr_clients[i].limit_bw_percentage = 100;
436                 break;
437         case TEGRA_CHIPID_TEGRA18:
438                 cinfo = tegra18x_isoclients;
439                 len = ARRAY_SIZE(tegra18x_isoclients);
440                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
441                         if ((i == TEGRA_ISO_CLIENT_VI_0) ||
442                                         (i == TEGRA_ISO_CLIENT_VI_1))
443                                 isomgr_clients[i].limit_bw_percentage = 10;
444                         else
445                                 isomgr_clients[i].limit_bw_percentage = 100;
446                 }
447                 break;
448         default:
449                 cinfo = tegra_null_isoclients;
450                 len = 0;
451                 break;
452         }
453
454         if (length)
455                 *length = len;
456
457         return cinfo;
458 }
459 /* get minimum MC frequency for client that can support this BW and LT */
460 static inline u32 mc_min_freq(u32 ubw, u32 ult) /* in KB/sec and usec */
461 {
462         unsigned int min_freq = 0;
463
464         /* ult==0 means ignore LT (effectively infinite) */
465         if (ubw == 0)
466                 goto out;
467
468 #ifdef CONFIG_COMMON_CLK
469         min_freq = bwmgr_bw_to_freq(ubw);
470 #else
471         min_freq = tegra_emc_bw_to_freq_req(ubw);
472 #endif
473
474 out:
475         return min_freq; /* return value in KHz*/
476 }
477
478 /* get dvfs switch latency for client requiring this frequency */
479 static inline u32 mc_dvfs_latency(u32 ufreq)
480 {
481 #ifdef CONFIG_COMMON_CLK
482         return bwmgr_dvfs_latency(ufreq);
483 #else
484         return tegra_emc_dvfs_latency(ufreq); /* return value in usec */
485 #endif
486 }
487
488 static inline void isomgr_lock(void)
489 {
490         BUG_ON(isomgr.task == current); /* disallow rentrance, avoid deadlock */
491         mutex_lock(&isomgr.lock);
492         isomgr.task = current;
493 }
494
495 static inline void isomgr_unlock(void)
496 {
497         BUG_ON(isomgr.task != current); /* detect mismatched calls */
498         isomgr.task = NULL;
499         mutex_unlock(&isomgr.lock);
500 }
501
502 /* call with isomgr_lock held. */
503 static void update_mc_clock(void)
504 {
505         int i;
506         u64 floor_freq;
507
508         BUG_ON(mutex_trylock(&isomgr.lock));
509         /* determine worst case freq to satisfy LT */
510         isomgr.lt_mf = 0;
511         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
512                 isomgr.lt_mf = max(isomgr.lt_mf, isomgr_clients[i].real_mf);
513
514         /* request the floor freq to satisfy LT */
515         if (isomgr.lt_mf_rq != isomgr.lt_mf) {
516 #ifdef CONFIG_COMMON_CLK
517                 if (!tegra_bwmgr_set_emc(isomgr.bwmgr_handle,
518                                 isomgr.lt_mf * 1000,
519                                 TEGRA_BWMGR_SET_EMC_FLOOR))
520                         isomgr.lt_mf_rq = isomgr.lt_mf;
521 #else
522                 if (!clk_set_rate(isomgr.emc_clk, isomgr.lt_mf * 1000)) {
523
524                         if (isomgr.lt_mf_rq == 0)
525                                 clk_enable(isomgr.emc_clk);
526                         isomgr.lt_mf_rq = isomgr.lt_mf;
527                         if (isomgr.lt_mf_rq == 0)
528                                 clk_disable(isomgr.emc_clk);
529                 }
530 #endif
531         }
532
533         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
534                 if (isomgr_clients[i].real_mf != isomgr_clients[i].real_mf_rq) {
535                         /* Ignore clocks for clients that are non-existent. */
536 #ifdef CONFIG_COMMON_CLK
537                         if (!isomgr_clients[i].bwmgr_handle)
538                                 continue;
539                         /* Each client's request is limited to
540                          * limit_bw_percentage% of current DRAM BW. A floor
541                          * request is made by each client to hold DRAM freq
542                          * high enough such that
543                          * DRAM_freq > client's req_bw/limit_bw_percentage
544                          */
545                         if (isomgr_clients[i].limit_bw_percentage != 100) {
546                                 floor_freq = (u64)isomgr_clients[i].real_mf
547                                         * 1000 * 100;
548                                 floor_freq = floor_freq /
549                                 (u64)isomgr_clients[i].limit_bw_percentage;
550                                 tegra_bwmgr_set_emc(
551                                         isomgr_clients[i].bwmgr_handle,
552                                         floor_freq,
553                                         TEGRA_BWMGR_SET_EMC_FLOOR);
554                         }
555                         if (!tegra_bwmgr_set_emc(
556                                         isomgr_clients[i].bwmgr_handle,
557                                         isomgr_clients[i].real_mf * 1000,
558                                         TEGRA_BWMGR_SET_EMC_SHARED_BW_ISO))
559                                 isomgr_clients[i].real_mf_rq =
560                                         isomgr_clients[i].real_mf;
561 #else
562                         if (!isomgr_clients[i].emc_clk)
563                                 continue;
564
565                         if (clk_set_rate(isomgr_clients[i].emc_clk,
566                                          isomgr_clients[i].real_mf * 1000))
567                                 continue;
568
569                         if (isomgr_clients[i].real_mf_rq == 0)
570                                 clk_enable(isomgr_clients[i].emc_clk);
571                         isomgr_clients[i].real_mf_rq =
572                                 isomgr_clients[i].real_mf;
573                         if (isomgr_clients[i].real_mf_rq == 0)
574                                 clk_disable(isomgr_clients[i].emc_clk);
575 #endif
576                 }
577         }
578 }
579
580 static void purge_isomgr_client(struct isomgr_client *cp)
581 {
582         cp->magic = 0;
583         atomic_set(&cp->kref.refcount, 0);
584         cp->dedi_bw = 0;
585         cp->rsvd_bw = 0;
586         cp->real_bw = 0;
587         cp->rsvd_mf = 0;
588         cp->real_mf = 0;
589         cp->renegotiate = NULL;
590         cp->realize = false;
591         cp->priv = NULL;
592         cp->sleep_bw = 0;
593         cp->margin_bw = 0;
594 }
595
596 static void unregister_iso_client(struct kref *kref)
597 {
598         struct isomgr_client *cp = container_of(kref,
599                                         struct isomgr_client, kref);
600         int client = cp - &isomgr_clients[0];
601
602         trace_tegra_isomgr_unregister_iso_client(cname[client], "enter");
603         isomgr_lock();
604         BUG_ON(cp->realize);
605
606         if (cp->real_bw > cp->margin_bw)
607                 isomgr.avail_bw += cp->real_bw;
608         else
609                 isomgr.avail_bw += cp->margin_bw;
610         isomgr.dedi_bw -= cp->dedi_bw;
611         purge_isomgr_client(cp);
612         update_mc_clock();
613         isomgr_unlock();
614
615         isomgr_scatter(client); /* share the excess */
616         trace_tegra_isomgr_unregister_iso_client(cname[client], "exit");
617 }
618
619 static void isomgr_scatter(int client)
620 {
621         struct isomgr_client *cp;
622         int i;
623
624         trace_tegra_isomgr_scatter(client, 0, cname[client], "enter");
625         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; ++i) {
626                 cp = &isomgr_clients[i];
627                 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
628                         continue;
629                 if (cp->renegotiate && i != client) {
630                         int avail_bw = cp->real_bw + isomgr.avail_bw -
631                                         isomgr.sleep_bw;
632                         if (avail_bw > cp->dedi_bw) {
633                                 trace_tegra_isomgr_scatter(client, 0,
634                                         cname[client], "scatter");
635                                 /* poke flexibles */
636                                 cp->renegotiate(cp->priv, avail_bw);
637                         }
638                 }
639                 kref_put(&cp->kref, unregister_iso_client);
640         }
641         trace_tegra_isomgr_scatter(client, 0, cname[client], "exit");
642 }
643
644 static void isomgr_scavenge(enum tegra_iso_client client)
645 {
646         struct isomgr_client *cp;
647         int i;
648
649         trace_tegra_isomgr_scavenge(client, 0, cname[client], "enter");
650         /* ask flexible clients above dedicated BW levels to pitch in */
651         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; ++i) {
652                 cp = &isomgr_clients[i];
653                 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
654                         continue;
655                 if (cp->renegotiate)
656                         if (cp->real_bw > cp->dedi_bw && i != client &&
657                             !cp->realize) {
658                                 int avail_bw = cp->real_bw + isomgr.avail_bw -
659                                                 isomgr.sleep_bw;
660                                 avail_bw = avail_bw < cp->dedi_bw ?
661                                            cp->dedi_bw : avail_bw;
662                                 trace_tegra_isomgr_scavenge(client, 0,
663                                         cname[client], "renego");
664                                 cp->renegotiate(cp->priv, avail_bw);
665                         }
666                 kref_put(&cp->kref, unregister_iso_client);
667         }
668         trace_tegra_isomgr_scavenge(client, 0, cname[client], "exit");
669 }
670
671 static bool is_client_valid(enum tegra_iso_client client)
672 {
673         if (unlikely(client < 0 ||
674                         client >= TEGRA_ISO_CLIENT_COUNT ||
675                         !client_valid[client] ||
676 #ifdef CONFIG_COMMON_CLK
677                         !isomgr_clients[client].bwmgr_handle))
678 #else
679                         !isomgr_clients[client].emc_clk))
680 #endif
681                 return false;
682         return true;
683 }
684
685 static tegra_isomgr_handle __tegra_isomgr_register(
686                         enum tegra_iso_client client, u32 udedi_bw,
687                         tegra_isomgr_renegotiate renegotiate, void *priv)
688 {
689         s32 dedi_bw = udedi_bw;
690         struct isomgr_client *cp = NULL;
691
692         VALIDATE_CLIENT();
693         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
694                 priv, cname[client], "enter");
695
696         if (unlikely(!udedi_bw && !renegotiate))
697                 goto validation_fail;
698
699         isomgr_lock();
700         cp = &isomgr_clients[client];
701
702         if (unlikely(atomic_read(&cp->kref.refcount)))
703                 goto fail_unlock;
704
705         if (unlikely(dedi_bw > isomgr.max_iso_bw - isomgr.dedi_bw)) {
706 #ifdef CONFIG_TEGRA_ISOMGR_MAX_ISO_BW_QUIRK
707                 int i;
708                 WARN(1, "max_iso_bw is relaxed to %dKB from %dKB",
709                         dedi_bw + isomgr.dedi_bw, isomgr.max_iso_bw);
710                 isomgr.avail_bw += dedi_bw + isomgr.dedi_bw -
711                                    isomgr.max_iso_bw;
712                 isomgr.max_iso_bw = dedi_bw + isomgr.dedi_bw;
713                 pr_info("ISO BW usage:\n");
714                 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
715                         if (!client_valid[i])
716                                 continue;
717                         pr_info("client=%s, iso dedi bw=%dKB\n",
718                                 cname[i],
719                                 (client == i) ? dedi_bw :
720                                 isomgr_clients[i].dedi_bw);
721                 }
722                 pr_info("revisit BW usage of iso clients\n");
723 #else
724                 pr_err("iso bandwidth %uKB is not available, client %s\n",
725                         dedi_bw, cname[client]);
726                 goto fail_unlock;
727 #endif
728         }
729
730         purge_isomgr_client(cp);
731         cp->magic = ISOMGR_MAGIC;
732         kref_init(&cp->kref);
733         cp->dedi_bw = dedi_bw;
734         cp->renegotiate = renegotiate;
735         cp->priv = priv;
736         isomgr.dedi_bw += dedi_bw;
737
738         isomgr_unlock();
739         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
740                 priv, cname[client], "exit");
741         return (tegra_isomgr_handle)cp;
742
743 fail_unlock:
744         isomgr_unlock();
745 validation_fail:
746         trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
747                 priv, cname[client], "inv_args_exit");
748         return ERR_PTR(-EINVAL);
749 }
750
751 /**
752  * tegra_isomgr_register - register an ISO BW client.
753  *
754  * @client      client to register as an ISO client.
755  * @udedi_bw    minimum bw client can work at. This bw is guarnteed to be
756  *              available for client when ever client need it. Client can
757  *              always request for more bw and client can get it based on
758  *              availability of bw in the system. udedi_bw is specified in KB.
759  * @renegotiate callback function to be called to renegotiate for bw.
760  *              client with no renegotiate callback provided can't allocate
761  *              bw more than udedi_bw.
762  *              Client with renegotiate callback can allocate more than
763  *              udedi_bw and release it during renegotiate callback, when
764  *              other clients in the system need their bw back.
765  *              renegotiate callback is called in two cases. 1. The isomgr
766  *              has excess bw, checking client to see if they need more bw.
767  *              2. The isomgr is out of bw and other clients need their udedi_bw
768  *              back. In this case, the client, which is using higher bw need to
769  *              release the bw and fallback to low(udedi_bw) bw use case.
770  * @priv        pointer to renegotiate callback function.
771  *
772  * @return      returns valid handle on successful registration.
773  * @retval      -EINVAL invalid arguments passed.
774  */
775 tegra_isomgr_handle tegra_isomgr_register(enum tegra_iso_client client,
776                                           u32 udedi_bw,
777                                           tegra_isomgr_renegotiate renegotiate,
778                                           void *priv)
779 {
780         if (test_mode)
781                 return (tegra_isomgr_handle)1;
782         return __tegra_isomgr_register(client, udedi_bw, renegotiate, priv);
783 }
784 EXPORT_SYMBOL(tegra_isomgr_register);
785
786 static void __tegra_isomgr_unregister(tegra_isomgr_handle handle)
787 {
788         struct isomgr_client *cp = (struct isomgr_client *)handle;
789         int client = cp - &isomgr_clients[0];
790
791         VALIDATE_HANDLE();
792         trace_tegra_isomgr_unregister(handle, cname[client]);
793         kref_put(&cp->kref, unregister_iso_client);
794 validation_fail:
795         return;
796 }
797
798 /**
799  * tegra_isomgr_unregister - unregister an ISO BW client.
800  *
801  * @handle      handle acquired during tegra_isomgr_register.
802  */
803 void tegra_isomgr_unregister(tegra_isomgr_handle handle)
804 {
805         if (test_mode)
806                 return;
807         __tegra_isomgr_unregister(handle);
808 }
809 EXPORT_SYMBOL(tegra_isomgr_unregister);
810
811 static u32 __tegra_isomgr_reserve(tegra_isomgr_handle handle,
812                          u32 ubw, u32 ult)
813 {
814         s32 bw = ubw;
815         u64 bw_check;
816         u32 mf, max_emc_bw, dvfs_latency = 0;
817         struct isomgr_client *cp = (struct isomgr_client *) handle;
818         int client = cp - &isomgr_clients[0];
819
820         VALIDATE_HANDLE();
821
822         isomgr_lock();
823         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
824                 goto handle_unregistered;
825
826         if (cp->rsvd_bw == ubw && cp->lti == ult) {
827                 kref_put(&cp->kref, unregister_iso_client);
828                 isomgr_unlock();
829                 return cp->lto;
830         }
831
832         trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client], "enter");
833
834         if (unlikely(cp->realize))
835                 goto out;
836
837         if (bw <= cp->margin_bw)
838                 goto bw_limit_check;
839
840         if (unlikely(!cp->renegotiate && bw > cp->dedi_bw))
841                 goto out;
842
843         if (bw > cp->dedi_bw &&
844             bw > isomgr.avail_bw + cp->real_bw - isomgr.sleep_bw)
845                 goto out;
846
847 bw_limit_check:
848         /* During reserve, check if BW request is within limit_bw_percentage%
849          * of max emc bw. Using max emc bw to find if the request is possible
850          * when we raise the freq to max possible value. If not, the reserve
851          * call will fail
852          */
853 #ifdef CONFIG_COMMON_CLK
854         max_emc_bw = bwmgr_freq_to_bw(tegra_bwmgr_get_max_emc_rate() / 1000);
855 #else
856         max_emc_bw = tegra_emc_freq_req_to_bw(
857                 clk_round_rate(clk_get_parent(isomgr.emc_clk), ULONG_MAX)
858                 / 1000);
859 #endif
860         bw_check = ((u64)max_emc_bw * (u64)(cp->limit_bw_percentage) / 100);
861         if (bw > bw_check)
862                 goto out;
863         /* Look up MC's min freq that could satisfy requested BW and LT */
864         mf = mc_min_freq(ubw, ult);
865         /* Look up MC's dvfs latency at min freq */
866         dvfs_latency = mc_dvfs_latency(mf);
867
868         cp->lti = ult;          /* remember client spec'd LT (usec) */
869         cp->lto = dvfs_latency; /* remember MC calculated LT (usec) */
870         cp->rsvd_mf = mf;       /* remember associated min freq */
871         cp->rsvd_bw = bw;
872 out:
873         kref_put(&cp->kref, unregister_iso_client);
874         isomgr_unlock();
875         trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client],
876                 dvfs_latency ? "exit" : "rsrv_fail_exit");
877         return dvfs_latency;
878 handle_unregistered:
879         isomgr_unlock();
880         trace_tegra_isomgr_reserve(handle, ubw, ult,
881                 cname[client], "inv_handle_exit");
882         return dvfs_latency;
883 validation_fail:
884         trace_tegra_isomgr_reserve(handle, ubw, ult, "unk", "inv_handle_exit");
885         return dvfs_latency;
886 }
887
888 /**
889  * tegra_isomgr_reserve - reserve bw for the ISO client.
890  *
891  * @handle      handle acquired during tegra_isomgr_register.
892  * @ubw         bandwidth in KBps.
893  * @ult         latency that can be tolerated by client in usec.
894  *
895  * returns dvfs latency thresh in usec.
896  * return 0 indicates that reserve failed.
897  */
898 u32 tegra_isomgr_reserve(tegra_isomgr_handle handle,
899                          u32 ubw, u32 ult)
900 {
901         if (test_mode)
902                 return 1;
903         return __tegra_isomgr_reserve(handle, ubw, ult);
904 }
905 EXPORT_SYMBOL(tegra_isomgr_reserve);
906
907 static u32 __tegra_isomgr_realize(tegra_isomgr_handle handle)
908 {
909         bool retry = false;
910         u32 dvfs_latency = 0;
911         s32 delta_bw = 0;
912         struct isomgr_client *cp = (struct isomgr_client *) handle;
913         int client = cp - &isomgr_clients[0];
914
915         VALIDATE_HANDLE();
916
917 retry:
918         isomgr_lock();
919         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
920                 goto handle_unregistered;
921
922         if (cp->rsvd_bw == cp->real_bw && cp->rsvd_mf == cp->real_mf) {
923                 kref_put(&cp->kref, unregister_iso_client);
924                 isomgr_unlock();
925                 return cp->lto;
926         }
927
928         if (!retry)
929                 trace_tegra_isomgr_realize(handle, cname[client], "enter");
930         if (cp->margin_bw < cp->real_bw)
931                 isomgr.avail_bw += cp->real_bw - cp->margin_bw;
932         cp->real_bw = 0;
933         cp->realize = true;
934         BUG_ON(isomgr.avail_bw > isomgr.max_iso_bw);
935
936         if (cp->rsvd_bw <= cp->margin_bw) {
937                 BUG_ON(cp->sleep_bw);
938                 cp->real_bw = cp->rsvd_bw; /* reservation has been realized */
939                 cp->real_mf = cp->rsvd_mf; /* minimum frequency realized */
940         } else if (cp->rsvd_bw <= isomgr.avail_bw + cp->margin_bw) {
941                 delta_bw = cp->rsvd_bw - cp->margin_bw;
942                 isomgr.avail_bw -= delta_bw;
943                 cp->real_bw = cp->rsvd_bw; /* reservation has been realized */
944                 cp->real_mf = cp->rsvd_mf; /* minimum frequency realized */
945                 if (cp->sleep_bw) {
946                         isomgr.sleep_bw -= delta_bw;
947                         cp->sleep_bw -= delta_bw;
948                         BUG_ON(cp->sleep_bw);
949                 }
950                 BUG_ON(isomgr.avail_bw < 0);
951                 SANITY_CHECK_AVAIL_BW();
952         } else {
953                 /* Protection from first scavenge failure */
954                 if (!cp->sleep_bw) {
955                         delta_bw = cp->rsvd_bw - cp->margin_bw;
956                         SANITY_CHECK_AVAIL_BW();
957                         isomgr.sleep_bw += delta_bw;
958                         BUG_ON(cp->sleep_bw);
959                         cp->sleep_bw += delta_bw;
960                 }
961                 kref_put(&cp->kref, unregister_iso_client);
962                 isomgr_unlock();
963                 isomgr_scavenge(client);
964                 retry = true;
965                 goto retry;
966         }
967
968         dvfs_latency = (u32)cp->lto;
969         cp->realize = false;
970         update_mc_clock();
971
972         kref_put(&cp->kref, unregister_iso_client);
973         isomgr_unlock();
974         trace_tegra_isomgr_realize(handle, cname[client],
975                 dvfs_latency ? "exit" : "real_fail_exit");
976         return dvfs_latency;
977 handle_unregistered:
978         isomgr_unlock();
979         trace_tegra_isomgr_realize(handle, cname[client], "inv_handle_exit");
980         return dvfs_latency;
981 validation_fail:
982         trace_tegra_isomgr_realize(handle, "unk", "inv_handle_exit");
983         return dvfs_latency;
984 }
985
986 /**
987  * tegra_isomgr_realize - realize the bw reserved by client.
988  *
989  * @handle      handle acquired during tegra_isomgr_register.
990  *
991  * returns dvfs latency thresh in usec.
992  * return 0 indicates that realize failed.
993  */
994 u32 tegra_isomgr_realize(tegra_isomgr_handle handle)
995 {
996         if (test_mode)
997                 return 1;
998         return __tegra_isomgr_realize(handle);
999 }
1000 EXPORT_SYMBOL(tegra_isomgr_realize);
1001
1002 static int __tegra_isomgr_set_margin(enum tegra_iso_client client,
1003                                         u32 bw, bool wait)
1004 {
1005         int ret = -EINVAL;
1006         s32 high_bw;
1007         struct isomgr_client *cp = NULL;
1008
1009         trace_tegra_isomgr_set_margin(client, bw, wait, "enter");
1010         VALIDATE_CLIENT();
1011
1012 retry:
1013         isomgr_lock();
1014         cp = &isomgr_clients[client];
1015         if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
1016                 goto handle_unregistered;
1017
1018         if (bw > cp->dedi_bw)
1019                 goto out;
1020
1021         if (bw <= cp->real_bw) {
1022                 if (cp->margin_bw > cp->real_bw)
1023                         isomgr.avail_bw += cp->margin_bw - cp->real_bw;
1024                 cp->margin_bw = bw;
1025         } else if (bw <= cp->margin_bw) {
1026                 BUG_ON(cp->margin_bw > cp->real_bw);
1027                 isomgr.avail_bw += cp->margin_bw - bw;
1028                 cp->margin_bw = bw;
1029                 BUG_ON(cp->margin_bw > cp->real_bw);
1030         } else if (bw > cp->margin_bw) {
1031                 high_bw = (cp->margin_bw > cp->real_bw) ?
1032                                 cp->margin_bw : cp->real_bw;
1033                 if (bw - high_bw <= isomgr.avail_bw - isomgr.sleep_bw) {
1034                         isomgr.avail_bw -= bw - high_bw;
1035                         cp->margin_bw = bw;
1036                 } else {
1037                         if (wait) {
1038                                 kref_put(&cp->kref, unregister_iso_client);
1039                                 isomgr_unlock();
1040                                 wait = false;
1041                                 isomgr_scavenge(client);
1042                                 goto retry;
1043                         }
1044                         ret = -ENOMEM;
1045                         goto out;
1046                 }
1047         }
1048         ret = 0;
1049 out:
1050         kref_put(&cp->kref, unregister_iso_client);
1051         isomgr_unlock();
1052         trace_tegra_isomgr_set_margin(client, bw, wait,
1053                                         ret ? "fail_exit" : "exit");
1054         return ret;
1055 handle_unregistered:
1056         isomgr_unlock();
1057 validation_fail:
1058         trace_tegra_isomgr_set_margin(client, bw, wait, "inv_arg_fail");
1059         return ret;
1060 }
1061
1062 /**
1063  * This sets bw aside for the client specified.
1064  * This bw can never be used for other clients needs.
1065  * margin bw, if not zero, should always be greater than equal to
1066  * reserved/realized bw.
1067  *
1068  * @client client
1069  * @bw bw margin KB.
1070  * @wait if true and bw is not available, it would wait till bw is available.
1071  *        if false, it would return immediately with success or failure.
1072  *
1073  * @retval  0 operation is successful.
1074  * @retval -ENOMEM Iso Bw requested is not avialable.
1075  * @retval -EINVAL Invalid arguments, bw is less than reserved/realized bw.
1076  */
1077 int tegra_isomgr_set_margin(enum tegra_iso_client client, u32 bw, bool wait)
1078 {
1079         if (test_mode)
1080                 return 0;
1081         return __tegra_isomgr_set_margin(client, bw, wait);
1082 }
1083 EXPORT_SYMBOL(tegra_isomgr_set_margin);
1084
1085 static int __tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1086 {
1087         int ret = -EINVAL;
1088
1089         if (unlikely(!is_client_valid(client)))
1090                 return ret;
1091
1092         /* FIXME: get this from renegotiable clients(display driver). */
1093         ret = 100;
1094         if (isomgr.avail_bw >= bw)
1095                 ret = 0;
1096         trace_tegra_isomgr_get_imp_time(client, bw, ret, cname[client]);
1097         return ret;
1098 }
1099
1100 /**
1101  * Returns the imp time required to realize the bw request.
1102  * The time returned is an approximate. It is possible that imp
1103  * time is returned as zero and still realize would be blocked for
1104  * non-zero time in realize call.
1105  *
1106  * @client      client id
1107  * @bw          bw in KB/sec
1108  *
1109  * @returns     time in milliseconds.
1110  * @retval      -EINVAL, client id is invalid.
1111  */
1112 int tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1113 {
1114         if (test_mode)
1115                 return 0;
1116         return __tegra_isomgr_get_imp_time(client, bw);
1117 }
1118 EXPORT_SYMBOL(tegra_isomgr_get_imp_time);
1119
1120 static u32 __tegra_isomgr_get_available_iso_bw(void)
1121 {
1122         trace_tegra_isomgr_get_available_iso_bw(isomgr.avail_bw);
1123         return isomgr.avail_bw;
1124 }
1125
1126 /**
1127  * Returns available iso bw at the time of calling this API.
1128  *
1129  * @returns     available bw in KB/sec.
1130  */
1131 u32 tegra_isomgr_get_available_iso_bw(void)
1132 {
1133         if (test_mode)
1134                 return UINT_MAX;
1135         return __tegra_isomgr_get_available_iso_bw();
1136 }
1137 EXPORT_SYMBOL(tegra_isomgr_get_available_iso_bw);
1138
1139 static u32 __tegra_isomgr_get_total_iso_bw(void)
1140 {
1141         trace_tegra_isomgr_get_total_iso_bw(isomgr.max_iso_bw);
1142         return isomgr.max_iso_bw;
1143 }
1144
1145 /**
1146  * Returns total iso bw in the system.
1147  *
1148  * @returns     total bw in KB/sec.
1149  */
1150 u32 tegra_isomgr_get_total_iso_bw(void)
1151 {
1152         if (test_mode)
1153                 return UINT_MAX;
1154         return __tegra_isomgr_get_total_iso_bw();
1155 }
1156 EXPORT_SYMBOL(tegra_isomgr_get_total_iso_bw);
1157
1158 #ifdef CONFIG_TEGRA_ISOMGR_SYSFS
1159 static ssize_t isomgr_show(struct kobject *kobj,
1160         struct kobj_attribute *attr, char *buf);
1161
1162 static const struct kobj_attribute lt_mf_attr =
1163         __ATTR(lt_mf, 0444, isomgr_show, NULL);
1164 static const struct kobj_attribute avail_bw_attr =
1165         __ATTR(avail_bw, 0444, isomgr_show, NULL);
1166 static const struct kobj_attribute max_iso_bw_attr =
1167         __ATTR(max_iso_bw, 0444, isomgr_show, NULL);
1168 static const struct kobj_attribute version_attr =
1169         __ATTR(version, 0444, isomgr_show, NULL);
1170
1171 static const struct attribute *isomgr_attrs[] = {
1172         &lt_mf_attr.attr,
1173         &avail_bw_attr.attr,
1174         &max_iso_bw_attr.attr,
1175         &version_attr.attr,
1176         NULL
1177 };
1178
1179 static ssize_t isomgr_show(struct kobject *kobj,
1180         struct kobj_attribute *attr, char *buf)
1181 {
1182         ssize_t rval = 0;
1183
1184         if (attr == &lt_mf_attr)
1185                 rval = sprintf(buf, "%dKHz\n", isomgr.lt_mf);
1186         else if (attr == &avail_bw_attr)
1187                 rval = sprintf(buf, "%dKB\n", isomgr.avail_bw);
1188         else if (attr == &max_iso_bw_attr)
1189                 rval = sprintf(buf, "%dKB\n", isomgr.max_iso_bw);
1190         else if (attr == &version_attr)
1191                 rval = sprintf(buf, "%d\n", ISOMGR_SYSFS_VERSION);
1192         return rval;
1193 }
1194
1195 static ssize_t isomgr_client_show(struct kobject *kobj,
1196         struct kobj_attribute *attr, char *buf)
1197 {
1198         int client = ((char *)attr - (char *)isomgr_clients) /
1199                         sizeof(struct isomgr_client);
1200         struct isomgr_client *cp =
1201                         (struct isomgr_client *)&isomgr_clients[client];
1202         ssize_t rval = 0;
1203
1204         if (attr == &cp->client_attrs.dedi_bw)
1205                 rval = sprintf(buf, "%dKB\n", cp->dedi_bw);
1206         else if (attr == &cp->client_attrs.rsvd_bw)
1207                 rval = sprintf(buf, "%dKB\n", cp->rsvd_bw);
1208         else if (attr == &cp->client_attrs.real_bw)
1209                 rval = sprintf(buf, "%dKB\n", cp->real_bw);
1210         else if (attr == &cp->client_attrs.lti)
1211                 rval = sprintf(buf, "%dus\n", cp->lti);
1212         else if (attr == &cp->client_attrs.lto)
1213                 rval = sprintf(buf, "%dus\n", cp->lto);
1214         else if (attr == &cp->client_attrs.rsvd_mf)
1215                 rval = sprintf(buf, "%dKHz\n", cp->rsvd_mf);
1216         else if (attr == &cp->client_attrs.real_mf)
1217                 rval = sprintf(buf, "%dKHz\n", cp->real_mf);
1218         else if (attr == &cp->client_attrs.sleep_bw)
1219                 rval = sprintf(buf, "%dKB\n", cp->sleep_bw);
1220         else if (attr == &cp->client_attrs.margin_bw)
1221                 rval = sprintf(buf, "%dKB\n", cp->margin_bw);
1222         return rval;
1223 }
1224
1225 static const struct isomgr_client_attrs client_attrs = {
1226         __ATTR(dedi_bw, 0444, isomgr_client_show, NULL),
1227         __ATTR(rsvd_bw, 0444, isomgr_client_show, NULL),
1228         __ATTR(real_bw, 0444, isomgr_client_show, NULL),
1229         __ATTR(lti,     0444, isomgr_client_show, NULL),
1230         __ATTR(lto,     0444, isomgr_client_show, NULL),
1231         __ATTR(rsvd_mf, 0444, isomgr_client_show, NULL),
1232         __ATTR(real_mf, 0444, isomgr_client_show, NULL),
1233         __ATTR(sleep_bw, 0444, isomgr_client_show, NULL),
1234         __ATTR(margin_bw, 0444, isomgr_client_show, NULL),
1235 };
1236
1237 #define NCATTRS (sizeof(client_attrs) / sizeof(struct kobj_attribute))
1238 static const struct attribute *client_attr_list[][NCATTRS+1] = {
1239 #define CLIENT_ATTR(i)\
1240         {\
1241                 &isomgr_clients[i].client_attrs.dedi_bw.attr,\
1242                 &isomgr_clients[i].client_attrs.rsvd_bw.attr,\
1243                 &isomgr_clients[i].client_attrs.real_bw.attr,\
1244                 &isomgr_clients[i].client_attrs.lti.attr,\
1245                 &isomgr_clients[i].client_attrs.lto.attr,\
1246                 &isomgr_clients[i].client_attrs.rsvd_mf.attr,\
1247                 &isomgr_clients[i].client_attrs.real_mf.attr,\
1248                 &isomgr_clients[i].client_attrs.sleep_bw.attr,\
1249                 &isomgr_clients[i].client_attrs.margin_bw.attr,\
1250                 NULL\
1251         },
1252         CLIENT_ATTR(0)
1253         CLIENT_ATTR(1)
1254         CLIENT_ATTR(2)
1255         CLIENT_ATTR(3)
1256         CLIENT_ATTR(4)
1257         CLIENT_ATTR(5)
1258         CLIENT_ATTR(6)
1259         CLIENT_ATTR(7)
1260         CLIENT_ATTR(8)
1261         CLIENT_ATTR(9)
1262         CLIENT_ATTR(10)
1263         CLIENT_ATTR(11)
1264 };
1265
1266 static void isomgr_create_client(int client, const char *name)
1267 {
1268         struct isomgr_client *cp = &isomgr_clients[client];
1269
1270         /* If this error hits, more CLIENT_ATTR(x) need to be added
1271          * in the above array client_attr_list.
1272          */
1273         BUILD_BUG_ON(TEGRA_ISO_CLIENT_COUNT > 11);
1274         BUG_ON(!isomgr.kobj);
1275         BUG_ON(cp->client_kobj);
1276         cp->client_kobj = kobject_create_and_add(name, isomgr.kobj);
1277         if (!cp->client_kobj) {
1278                 pr_err("failed to create sysfs client dir\n");
1279                 return;
1280         }
1281         cp->client_attrs = client_attrs;
1282         if (sysfs_create_files(cp->client_kobj, &client_attr_list[client][0])) {
1283                 pr_err("failed to create sysfs client files\n");
1284                 kobject_del(cp->client_kobj);
1285                 return;
1286         }
1287 }
1288
1289 static void isomgr_create_sysfs(void)
1290 {
1291         int i;
1292
1293         BUG_ON(isomgr.kobj);
1294         isomgr.kobj = kobject_create_and_add("isomgr", kernel_kobj);
1295         if (!isomgr.kobj) {
1296                 pr_err("failed to create kobject\n");
1297                 return;
1298         }
1299         if (sysfs_create_files(isomgr.kobj, isomgr_attrs)) {
1300                 pr_err("failed to create sysfs files\n");
1301                 kobject_del(isomgr.kobj);
1302                 isomgr.kobj = NULL;
1303                 return;
1304         }
1305
1306         for (i = 0; i < isoclients; i++) {
1307                 if (isoclient_info[i].name)
1308                         isomgr_create_client(isoclient_info[i].client,
1309                                              isoclient_info[i].name);
1310         }
1311 }
1312 #else
1313 static inline void isomgr_create_sysfs(void) {};
1314 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
1315
1316 int __init isomgr_init(void)
1317 {
1318         int i;
1319         unsigned int max_emc_clk;
1320         unsigned int max_emc_bw;
1321
1322         mutex_init(&isomgr.lock);
1323         isoclient_info = get_iso_client_info(&isoclients);
1324
1325         for (i = 0; ; i++) {
1326                 if (isoclient_info[i].name)
1327                         client_valid[isoclient_info[i].client] = true;
1328                 else
1329                         break;
1330         }
1331
1332 #ifdef CONFIG_COMMON_CLK
1333         isomgr.bwmgr_handle = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_ISOMGR);
1334         if (IS_ERR_OR_NULL(isomgr.bwmgr_handle)) {
1335                 pr_err("couldn't get handle from bwmgr. disabling isomgr.\n");
1336 #else
1337         isomgr.emc_clk = clk_get_sys("iso", "emc");
1338         if (IS_ERR_OR_NULL(isomgr.emc_clk)) {
1339                 pr_err("couldn't find iso emc clock. disabling isomgr.\n");
1340 #endif
1341                 test_mode = 1;
1342                 return 0;
1343         }
1344
1345         if (!isomgr.max_iso_bw) {
1346 #ifdef CONFIG_COMMON_CLK
1347                 max_emc_clk = tegra_bwmgr_get_max_emc_rate() / 1000;
1348                 max_emc_bw = bwmgr_freq_to_bw(max_emc_clk);
1349                 isomgr.max_iso_bw = max_emc_bw *
1350                         bwmgr_iso_bw_percentage_max() / 100;
1351 #else
1352                 /* With DVFS disabled, bus children cannot get real max emc freq supported
1353                  * Only the root parent EMC node is set to max possible rate*/
1354                 max_emc_clk = clk_round_rate(clk_get_parent(isomgr.emc_clk), ULONG_MAX) / 1000;
1355                 max_emc_bw = tegra_emc_freq_req_to_bw(max_emc_clk);
1356                 /* ISO clients can use iso_bw_percentage of max emc bw. */
1357                 isomgr.max_iso_bw = max_emc_bw * iso_bw_percentage / 100;
1358 #endif
1359                 pr_info("iso emc max clk=%dKHz\n", max_emc_clk);
1360                 pr_info("max_iso_bw=%dKB\n", isomgr.max_iso_bw);
1361                 isomgr.avail_bw = isomgr.max_iso_bw;
1362         }
1363
1364         for (i = 0; i < isoclients; i++) {
1365                 if (isoclient_info[i].name) {
1366                         enum tegra_iso_client c = isoclient_info[i].client;
1367
1368                         atomic_set(&isomgr_clients[c].kref.refcount, 0);
1369                         init_completion(&isomgr_clients[c].cmpl);
1370 #ifdef CONFIG_COMMON_CLK
1371                         isomgr_clients[c].bwmgr_handle = tegra_bwmgr_register(
1372                                         isoclient_info[i].bwmgr_id);
1373
1374                         if (IS_ERR_OR_NULL(isomgr_clients[c].bwmgr_handle)) {
1375                                 pr_err("couldn't get %s's bwmgr handle\n",
1376                                                 isoclient_info[i].name);
1377                                 isomgr_clients[c].bwmgr_handle = NULL;
1378 #else
1379                         isomgr_clients[c].emc_clk = clk_get_sys(
1380                                         isoclient_info[i].dev_name,
1381                                         isoclient_info[i].emc_clk_name);
1382
1383                         if (IS_ERR_OR_NULL(isomgr_clients[c].emc_clk)) {
1384                                 pr_err("couldn't find %s %s clock",
1385                                         isoclient_info[i].dev_name,
1386                                         isoclient_info[i].emc_clk_name);
1387
1388                                 isomgr_clients[c].emc_clk = NULL;
1389 #endif
1390                                 return 0;
1391                         }
1392                 }
1393         }
1394
1395         isomgr_create_sysfs();
1396         return 0;
1397 }
1398 #ifdef CONFIG_COMMON_CLK
1399 fs_initcall(isomgr_init);
1400 #endif
1401
1402 int tegra_isomgr_enable_test_mode(void)
1403 {
1404         int i;
1405         struct isomgr_client *cp = NULL;
1406
1407         isomgr_lock();
1408         test_mode = 1;
1409         isomgr_unlock();
1410         for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
1411                 if (!client_valid[i])
1412                         continue;
1413                 cp = &isomgr_clients[i];
1414 retry:
1415                 __tegra_isomgr_unregister(cp);
1416                 if (atomic_read(&cp->kref.refcount))
1417                         goto retry;
1418         }
1419         return 0;
1420 }
1421 EXPORT_SYMBOL(tegra_isomgr_enable_test_mode);
1422
1423 tegra_isomgr_handle test_tegra_isomgr_register(enum tegra_iso_client client,
1424                                           u32 dedicated_bw,     /* KB/sec */
1425                                           tegra_isomgr_renegotiate renegotiate,
1426                                           void *priv)
1427 {
1428         return __tegra_isomgr_register(client, dedicated_bw, renegotiate, priv);
1429 }
1430 EXPORT_SYMBOL(test_tegra_isomgr_register);
1431
1432 void test_tegra_isomgr_unregister(tegra_isomgr_handle handle)
1433 {
1434         return __tegra_isomgr_unregister(handle);
1435 }
1436 EXPORT_SYMBOL(test_tegra_isomgr_unregister);
1437
1438 u32 test_tegra_isomgr_reserve(tegra_isomgr_handle handle,
1439                          u32 bw,        /* KB/sec */
1440                          u32 lt)        /* usec */
1441 {
1442         return __tegra_isomgr_reserve(handle, bw, lt);
1443 }
1444 EXPORT_SYMBOL(test_tegra_isomgr_reserve);
1445
1446 u32 test_tegra_isomgr_realize(tegra_isomgr_handle handle)
1447 {
1448         return __tegra_isomgr_realize(handle);
1449 }
1450 EXPORT_SYMBOL(test_tegra_isomgr_realize);
1451
1452 int test_tegra_isomgr_set_margin(enum tegra_iso_client client,
1453                                 u32 bw, bool wait)
1454 {
1455         return __tegra_isomgr_set_margin(client, bw, wait);
1456 }
1457 EXPORT_SYMBOL(test_tegra_isomgr_set_margin);
1458
1459 int test_tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1460 {
1461         return __tegra_isomgr_get_imp_time(client, bw);
1462 }
1463 EXPORT_SYMBOL(test_tegra_isomgr_get_imp_time);
1464
1465 u32 test_tegra_isomgr_get_available_iso_bw(void)
1466 {
1467         return __tegra_isomgr_get_available_iso_bw();
1468 }
1469 EXPORT_SYMBOL(test_tegra_isomgr_get_available_iso_bw);
1470
1471 u32 test_tegra_isomgr_get_total_iso_bw(void)
1472 {
1473         return __tegra_isomgr_get_total_iso_bw();
1474 }
1475 EXPORT_SYMBOL(test_tegra_isomgr_get_total_iso_bw);