2 * arch/arm/mach-tegra/isomgr.c
4 * Copyright (c) 2012-2016, NVIDIA CORPORATION. All rights reserved.
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.
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
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.
20 #define pr_fmt(fmt) "%s(): " fmt, __func__
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>
40 #include <linux/platform/tegra/isomgr.h>
42 #include <linux/platform/tegra/emc_bwmgr.h>
43 #ifdef CONFIG_COMMON_CLK
44 #include <linux/platform/tegra/bwmgr_mc.h>
46 #include <linux/platform/tegra/mc.h>
47 #include <linux/clk.h>
48 #include <linux/platform/tegra/clock.h>
51 #define CREATE_TRACE_POINTS
52 #include <trace/events/isomgr.h>
54 #define ISOMGR_SYSFS_VERSION 0 /* increment on change */
55 #define ISOMGR_DEBUG 1
58 #define SANITY_CHECK_AVAIL_BW() { \
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; \
66 t += isomgr_clients[idx].margin_bw; \
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); \
76 #define SANITY_CHECK_AVAIL_BW()
79 #define VALIDATE_HANDLE() \
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; \
88 #define VALIDATE_CLIENT() \
90 if (unlikely(!is_client_valid(client))) { \
91 pr_err("invalid client %d\n", client); \
92 goto validation_fail; \
96 /* To allow test code take over control */
97 static bool test_mode;
99 static char *cname[] = {
114 struct isoclient_info {
115 enum tegra_iso_client client;
119 enum tegra_bwmgr_client_id bwmgr_id;
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;
127 static struct isoclient_info tegra_null_isoclients[] = {
128 /* This must be last entry*/
130 .client = TEGRA_ISO_CLIENT_COUNT,
135 static struct isoclient_info tegra11x_isoclients[] = {
137 .client = TEGRA_ISO_CLIENT_DISP_0,
139 .dev_name = "tegradc.0",
140 .emc_clk_name = "emc",
143 .client = TEGRA_ISO_CLIENT_DISP_1,
145 .dev_name = "tegradc.1",
146 .emc_clk_name = "emc",
149 .client = TEGRA_ISO_CLIENT_VI_0,
152 .emc_clk_name = "emc",
154 /* This must be last entry*/
156 .client = TEGRA_ISO_CLIENT_COUNT,
161 static struct isoclient_info tegra14x_isoclients[] = {
163 .client = TEGRA_ISO_CLIENT_DISP_0,
165 .dev_name = "tegradc.0",
166 .emc_clk_name = "emc",
169 .client = TEGRA_ISO_CLIENT_DISP_1,
171 .dev_name = "tegradc.1",
172 .emc_clk_name = "emc",
175 .client = TEGRA_ISO_CLIENT_VI_0,
178 .emc_clk_name = "emc",
181 .client = TEGRA_ISO_CLIENT_BBC_0,
183 .dev_name = "tegra_bb.0",
184 .emc_clk_name = "emc_bw",
186 /* This must be last entry*/
188 .client = TEGRA_ISO_CLIENT_COUNT,
193 static struct isoclient_info tegra12x_isoclients[] = {
195 .client = TEGRA_ISO_CLIENT_DISP_0,
197 .dev_name = "tegradc.0",
198 .emc_clk_name = "emc",
201 .client = TEGRA_ISO_CLIENT_DISP_1,
203 .dev_name = "tegradc.1",
204 .emc_clk_name = "emc",
207 .client = TEGRA_ISO_CLIENT_VI_0,
209 .dev_name = "tegra_vi",
210 .emc_clk_name = "emc",
213 .client = TEGRA_ISO_CLIENT_ISP_A,
215 .dev_name = "tegra_isp.0",
216 .emc_clk_name = "emc",
219 .client = TEGRA_ISO_CLIENT_ISP_B,
221 .dev_name = "tegra_isp.1",
222 .emc_clk_name = "emc",
225 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
226 .name = "tegra_camera",
227 .dev_name = "tegra_camera_ctrl",
228 .emc_clk_name = "iso.emc",
230 /* This must be last entry*/
232 .client = TEGRA_ISO_CLIENT_COUNT,
237 static struct isoclient_info tegra21x_isoclients[] = {
239 .client = TEGRA_ISO_CLIENT_DISP_0,
241 .dev_name = "tegradc.0",
242 .emc_clk_name = "emc",
245 .client = TEGRA_ISO_CLIENT_DISP_1,
247 .dev_name = "tegradc.1",
248 .emc_clk_name = "emc",
251 .client = TEGRA_ISO_CLIENT_VI_0,
253 .dev_name = "tegra_vi",
254 .emc_clk_name = "emc",
257 .client = TEGRA_ISO_CLIENT_ISP_A,
259 .dev_name = "tegra_isp.0",
260 .emc_clk_name = "emc",
263 .client = TEGRA_ISO_CLIENT_ISP_B,
265 .dev_name = "tegra_isp.1",
266 .emc_clk_name = "emc",
269 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
270 .name = "tegra_camera",
271 .dev_name = "tegra_camera_ctrl",
272 .emc_clk_name = "iso.emc",
274 /* This must be last entry*/
276 .client = TEGRA_ISO_CLIENT_COUNT,
281 static struct isoclient_info tegra18x_isoclients[] = {
283 .client = TEGRA_ISO_CLIENT_DISP_0,
285 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP0,
288 .client = TEGRA_ISO_CLIENT_DISP_1,
290 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP1,
293 .client = TEGRA_ISO_CLIENT_DISP_2,
295 .bwmgr_id = TEGRA_BWMGR_CLIENT_DISP2,
298 .client = TEGRA_ISO_CLIENT_VI_0,
300 .bwmgr_id = TEGRA_BWMGR_CLIENT_VI,
303 .client = TEGRA_ISO_CLIENT_ISP_A,
305 .bwmgr_id = TEGRA_BWMGR_CLIENT_ISPA,
308 .client = TEGRA_ISO_CLIENT_TEGRA_CAMERA,
310 .bwmgr_id = TEGRA_BWMGR_CLIENT_CAMERA,
313 .client = TEGRA_ISO_CLIENT_APE_ADMA,
315 .bwmgr_id = TEGRA_BWMGR_CLIENT_APE_ADMA,
318 .client = TEGRA_ISO_CLIENT_EQOS,
320 .bwmgr_id = TEGRA_BWMGR_CLIENT_EQOS,
322 /* This must be last entry*/
324 .client = TEGRA_ISO_CLIENT_COUNT,
329 static void isomgr_scatter(int client);
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
351 void *priv; /* client driver's private data */
352 struct completion cmpl; /* so we can sleep waiting for delta BW */
354 #ifdef CONFIG_COMMON_CLK
355 struct tegra_bwmgr_client *bwmgr_handle;
357 struct clk *emc_clk; /* client emc clk for bw */
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;
373 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
374 } isomgr_clients[TEGRA_ISO_CLIENT_COUNT];
377 struct mutex lock; /* to lock ALL isomgr state */
378 struct task_struct *task; /* check reentrant/mismatched locks */
380 #ifdef CONFIG_COMMON_CLK
381 struct tegra_bwmgr_client *bwmgr_handle;
383 struct clk *emc_clk; /* isomgr emc clock for floor freq */
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 */
394 .max_iso_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
395 .avail_bw = CONFIG_TEGRA_ISOMGR_POOL_KB_PER_SEC,
398 static struct isoclient_info *get_iso_client_info(int *length)
400 enum tegra_chipid cid;
401 struct isoclient_info *cinfo;
404 cid = tegra_get_chipid();
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;
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;
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;
428 case TEGRA_CHIPID_TEGRA21:
429 cinfo = tegra21x_isoclients;
430 iso_bw_percentage = 45; /* Hack: Should be determined based on
433 len = ARRAY_SIZE(tegra21x_isoclients);
434 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
435 isomgr_clients[i].limit_bw_percentage = 100;
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;
445 isomgr_clients[i].limit_bw_percentage = 100;
449 cinfo = tegra_null_isoclients;
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 */
462 unsigned int min_freq = 0;
464 /* ult==0 means ignore LT (effectively infinite) */
468 #ifdef CONFIG_COMMON_CLK
469 min_freq = bwmgr_bw_to_freq(ubw);
471 min_freq = tegra_emc_bw_to_freq_req(ubw);
475 return min_freq; /* return value in KHz*/
478 /* get dvfs switch latency for client requiring this frequency */
479 static inline u32 mc_dvfs_latency(u32 ufreq)
481 #ifdef CONFIG_COMMON_CLK
482 return bwmgr_dvfs_latency(ufreq);
484 return tegra_emc_dvfs_latency(ufreq); /* return value in usec */
488 static inline void isomgr_lock(void)
490 BUG_ON(isomgr.task == current); /* disallow rentrance, avoid deadlock */
491 mutex_lock(&isomgr.lock);
492 isomgr.task = current;
495 static inline void isomgr_unlock(void)
497 BUG_ON(isomgr.task != current); /* detect mismatched calls */
499 mutex_unlock(&isomgr.lock);
502 /* call with isomgr_lock held. */
503 static void update_mc_clock(void)
508 BUG_ON(mutex_trylock(&isomgr.lock));
509 /* determine worst case freq to satisfy LT */
511 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++)
512 isomgr.lt_mf = max(isomgr.lt_mf, isomgr_clients[i].real_mf);
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,
519 TEGRA_BWMGR_SET_EMC_FLOOR))
520 isomgr.lt_mf_rq = isomgr.lt_mf;
522 if (!clk_set_rate(isomgr.emc_clk, isomgr.lt_mf * 1000)) {
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);
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)
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
545 if (isomgr_clients[i].limit_bw_percentage != 100) {
546 floor_freq = (u64)isomgr_clients[i].real_mf
548 floor_freq = floor_freq /
549 (u64)isomgr_clients[i].limit_bw_percentage;
551 isomgr_clients[i].bwmgr_handle,
553 TEGRA_BWMGR_SET_EMC_FLOOR);
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;
562 if (!isomgr_clients[i].emc_clk)
565 if (clk_set_rate(isomgr_clients[i].emc_clk,
566 isomgr_clients[i].real_mf * 1000))
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);
580 static void purge_isomgr_client(struct isomgr_client *cp)
583 atomic_set(&cp->kref.refcount, 0);
589 cp->renegotiate = NULL;
596 static void unregister_iso_client(struct kref *kref)
598 struct isomgr_client *cp = container_of(kref,
599 struct isomgr_client, kref);
600 int client = cp - &isomgr_clients[0];
602 trace_tegra_isomgr_unregister_iso_client(cname[client], "enter");
606 if (cp->real_bw > cp->margin_bw)
607 isomgr.avail_bw += cp->real_bw;
609 isomgr.avail_bw += cp->margin_bw;
610 isomgr.dedi_bw -= cp->dedi_bw;
611 purge_isomgr_client(cp);
615 isomgr_scatter(client); /* share the excess */
616 trace_tegra_isomgr_unregister_iso_client(cname[client], "exit");
619 static void isomgr_scatter(int client)
621 struct isomgr_client *cp;
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)))
629 if (cp->renegotiate && i != client) {
630 int avail_bw = cp->real_bw + isomgr.avail_bw -
632 if (avail_bw > cp->dedi_bw) {
633 trace_tegra_isomgr_scatter(client, 0,
634 cname[client], "scatter");
636 cp->renegotiate(cp->priv, avail_bw);
639 kref_put(&cp->kref, unregister_iso_client);
641 trace_tegra_isomgr_scatter(client, 0, cname[client], "exit");
644 static void isomgr_scavenge(enum tegra_iso_client client)
646 struct isomgr_client *cp;
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)))
656 if (cp->real_bw > cp->dedi_bw && i != client &&
658 int avail_bw = cp->real_bw + isomgr.avail_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);
666 kref_put(&cp->kref, unregister_iso_client);
668 trace_tegra_isomgr_scavenge(client, 0, cname[client], "exit");
671 static bool is_client_valid(enum tegra_iso_client client)
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))
679 !isomgr_clients[client].emc_clk))
685 static tegra_isomgr_handle __tegra_isomgr_register(
686 enum tegra_iso_client client, u32 udedi_bw,
687 tegra_isomgr_renegotiate renegotiate, void *priv)
689 s32 dedi_bw = udedi_bw;
690 struct isomgr_client *cp = NULL;
693 trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
694 priv, cname[client], "enter");
696 if (unlikely(!udedi_bw && !renegotiate))
697 goto validation_fail;
700 cp = &isomgr_clients[client];
702 if (unlikely(atomic_read(&cp->kref.refcount)))
705 if (unlikely(dedi_bw > isomgr.max_iso_bw - isomgr.dedi_bw)) {
706 #ifdef CONFIG_TEGRA_ISOMGR_MAX_ISO_BW_QUIRK
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 -
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])
717 pr_info("client=%s, iso dedi bw=%dKB\n",
719 (client == i) ? dedi_bw :
720 isomgr_clients[i].dedi_bw);
722 pr_info("revisit BW usage of iso clients\n");
724 pr_err("iso bandwidth %uKB is not available, client %s\n",
725 dedi_bw, cname[client]);
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;
736 isomgr.dedi_bw += dedi_bw;
739 trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
740 priv, cname[client], "exit");
741 return (tegra_isomgr_handle)cp;
746 trace_tegra_isomgr_register(client, dedi_bw, renegotiate,
747 priv, cname[client], "inv_args_exit");
748 return ERR_PTR(-EINVAL);
752 * tegra_isomgr_register - register an ISO BW client.
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.
772 * @return returns valid handle on successful registration.
773 * @retval -EINVAL invalid arguments passed.
775 tegra_isomgr_handle tegra_isomgr_register(enum tegra_iso_client client,
777 tegra_isomgr_renegotiate renegotiate,
781 return (tegra_isomgr_handle)1;
782 return __tegra_isomgr_register(client, udedi_bw, renegotiate, priv);
784 EXPORT_SYMBOL(tegra_isomgr_register);
786 static void __tegra_isomgr_unregister(tegra_isomgr_handle handle)
788 struct isomgr_client *cp = (struct isomgr_client *)handle;
789 int client = cp - &isomgr_clients[0];
792 trace_tegra_isomgr_unregister(handle, cname[client]);
793 kref_put(&cp->kref, unregister_iso_client);
799 * tegra_isomgr_unregister - unregister an ISO BW client.
801 * @handle handle acquired during tegra_isomgr_register.
803 void tegra_isomgr_unregister(tegra_isomgr_handle handle)
807 __tegra_isomgr_unregister(handle);
809 EXPORT_SYMBOL(tegra_isomgr_unregister);
811 static u32 __tegra_isomgr_reserve(tegra_isomgr_handle handle,
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];
823 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
824 goto handle_unregistered;
826 if (cp->rsvd_bw == ubw && cp->lti == ult) {
827 kref_put(&cp->kref, unregister_iso_client);
832 trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client], "enter");
834 if (unlikely(cp->realize))
837 if (bw <= cp->margin_bw)
840 if (unlikely(!cp->renegotiate && bw > cp->dedi_bw))
843 if (bw > cp->dedi_bw &&
844 bw > isomgr.avail_bw + cp->real_bw - isomgr.sleep_bw)
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
853 #ifdef CONFIG_COMMON_CLK
854 max_emc_bw = bwmgr_freq_to_bw(tegra_bwmgr_get_max_emc_rate() / 1000);
856 max_emc_bw = tegra_emc_freq_req_to_bw(
857 clk_round_rate(clk_get_parent(isomgr.emc_clk), ULONG_MAX)
860 bw_check = ((u64)max_emc_bw * (u64)(cp->limit_bw_percentage) / 100);
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);
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 */
873 kref_put(&cp->kref, unregister_iso_client);
875 trace_tegra_isomgr_reserve(handle, ubw, ult, cname[client],
876 dvfs_latency ? "exit" : "rsrv_fail_exit");
880 trace_tegra_isomgr_reserve(handle, ubw, ult,
881 cname[client], "inv_handle_exit");
884 trace_tegra_isomgr_reserve(handle, ubw, ult, "unk", "inv_handle_exit");
889 * tegra_isomgr_reserve - reserve bw for the ISO client.
891 * @handle handle acquired during tegra_isomgr_register.
892 * @ubw bandwidth in KBps.
893 * @ult latency that can be tolerated by client in usec.
895 * returns dvfs latency thresh in usec.
896 * return 0 indicates that reserve failed.
898 u32 tegra_isomgr_reserve(tegra_isomgr_handle handle,
903 return __tegra_isomgr_reserve(handle, ubw, ult);
905 EXPORT_SYMBOL(tegra_isomgr_reserve);
907 static u32 __tegra_isomgr_realize(tegra_isomgr_handle handle)
910 u32 dvfs_latency = 0;
912 struct isomgr_client *cp = (struct isomgr_client *) handle;
913 int client = cp - &isomgr_clients[0];
919 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
920 goto handle_unregistered;
922 if (cp->rsvd_bw == cp->real_bw && cp->rsvd_mf == cp->real_mf) {
923 kref_put(&cp->kref, unregister_iso_client);
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;
934 BUG_ON(isomgr.avail_bw > isomgr.max_iso_bw);
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 */
946 isomgr.sleep_bw -= delta_bw;
947 cp->sleep_bw -= delta_bw;
948 BUG_ON(cp->sleep_bw);
950 BUG_ON(isomgr.avail_bw < 0);
951 SANITY_CHECK_AVAIL_BW();
953 /* Protection from first scavenge failure */
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;
961 kref_put(&cp->kref, unregister_iso_client);
963 isomgr_scavenge(client);
968 dvfs_latency = (u32)cp->lto;
972 kref_put(&cp->kref, unregister_iso_client);
974 trace_tegra_isomgr_realize(handle, cname[client],
975 dvfs_latency ? "exit" : "real_fail_exit");
979 trace_tegra_isomgr_realize(handle, cname[client], "inv_handle_exit");
982 trace_tegra_isomgr_realize(handle, "unk", "inv_handle_exit");
987 * tegra_isomgr_realize - realize the bw reserved by client.
989 * @handle handle acquired during tegra_isomgr_register.
991 * returns dvfs latency thresh in usec.
992 * return 0 indicates that realize failed.
994 u32 tegra_isomgr_realize(tegra_isomgr_handle handle)
998 return __tegra_isomgr_realize(handle);
1000 EXPORT_SYMBOL(tegra_isomgr_realize);
1002 static int __tegra_isomgr_set_margin(enum tegra_iso_client client,
1007 struct isomgr_client *cp = NULL;
1009 trace_tegra_isomgr_set_margin(client, bw, wait, "enter");
1014 cp = &isomgr_clients[client];
1015 if (unlikely(!atomic_inc_not_zero(&cp->kref.refcount)))
1016 goto handle_unregistered;
1018 if (bw > cp->dedi_bw)
1021 if (bw <= cp->real_bw) {
1022 if (cp->margin_bw > cp->real_bw)
1023 isomgr.avail_bw += cp->margin_bw - cp->real_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;
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;
1038 kref_put(&cp->kref, unregister_iso_client);
1041 isomgr_scavenge(client);
1050 kref_put(&cp->kref, unregister_iso_client);
1052 trace_tegra_isomgr_set_margin(client, bw, wait,
1053 ret ? "fail_exit" : "exit");
1055 handle_unregistered:
1058 trace_tegra_isomgr_set_margin(client, bw, wait, "inv_arg_fail");
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.
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.
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.
1077 int tegra_isomgr_set_margin(enum tegra_iso_client client, u32 bw, bool wait)
1081 return __tegra_isomgr_set_margin(client, bw, wait);
1083 EXPORT_SYMBOL(tegra_isomgr_set_margin);
1085 static int __tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1089 if (unlikely(!is_client_valid(client)))
1092 /* FIXME: get this from renegotiable clients(display driver). */
1094 if (isomgr.avail_bw >= bw)
1096 trace_tegra_isomgr_get_imp_time(client, bw, ret, cname[client]);
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.
1109 * @returns time in milliseconds.
1110 * @retval -EINVAL, client id is invalid.
1112 int tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1116 return __tegra_isomgr_get_imp_time(client, bw);
1118 EXPORT_SYMBOL(tegra_isomgr_get_imp_time);
1120 static u32 __tegra_isomgr_get_available_iso_bw(void)
1122 trace_tegra_isomgr_get_available_iso_bw(isomgr.avail_bw);
1123 return isomgr.avail_bw;
1127 * Returns available iso bw at the time of calling this API.
1129 * @returns available bw in KB/sec.
1131 u32 tegra_isomgr_get_available_iso_bw(void)
1135 return __tegra_isomgr_get_available_iso_bw();
1137 EXPORT_SYMBOL(tegra_isomgr_get_available_iso_bw);
1139 static u32 __tegra_isomgr_get_total_iso_bw(void)
1141 trace_tegra_isomgr_get_total_iso_bw(isomgr.max_iso_bw);
1142 return isomgr.max_iso_bw;
1146 * Returns total iso bw in the system.
1148 * @returns total bw in KB/sec.
1150 u32 tegra_isomgr_get_total_iso_bw(void)
1154 return __tegra_isomgr_get_total_iso_bw();
1156 EXPORT_SYMBOL(tegra_isomgr_get_total_iso_bw);
1158 #ifdef CONFIG_TEGRA_ISOMGR_SYSFS
1159 static ssize_t isomgr_show(struct kobject *kobj,
1160 struct kobj_attribute *attr, char *buf);
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);
1171 static const struct attribute *isomgr_attrs[] = {
1173 &avail_bw_attr.attr,
1174 &max_iso_bw_attr.attr,
1179 static ssize_t isomgr_show(struct kobject *kobj,
1180 struct kobj_attribute *attr, char *buf)
1184 if (attr == <_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);
1195 static ssize_t isomgr_client_show(struct kobject *kobj,
1196 struct kobj_attribute *attr, char *buf)
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];
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);
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),
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)\
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,\
1266 static void isomgr_create_client(int client, const char *name)
1268 struct isomgr_client *cp = &isomgr_clients[client];
1270 /* If this error hits, more CLIENT_ATTR(x) need to be added
1271 * in the above array client_attr_list.
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");
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);
1289 static void isomgr_create_sysfs(void)
1293 BUG_ON(isomgr.kobj);
1294 isomgr.kobj = kobject_create_and_add("isomgr", kernel_kobj);
1296 pr_err("failed to create kobject\n");
1299 if (sysfs_create_files(isomgr.kobj, isomgr_attrs)) {
1300 pr_err("failed to create sysfs files\n");
1301 kobject_del(isomgr.kobj);
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);
1313 static inline void isomgr_create_sysfs(void) {};
1314 #endif /* CONFIG_TEGRA_ISOMGR_SYSFS */
1316 int __init isomgr_init(void)
1319 unsigned int max_emc_clk;
1320 unsigned int max_emc_bw;
1322 mutex_init(&isomgr.lock);
1323 isoclient_info = get_iso_client_info(&isoclients);
1325 for (i = 0; ; i++) {
1326 if (isoclient_info[i].name)
1327 client_valid[isoclient_info[i].client] = true;
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");
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");
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;
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;
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;
1364 for (i = 0; i < isoclients; i++) {
1365 if (isoclient_info[i].name) {
1366 enum tegra_iso_client c = isoclient_info[i].client;
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);
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;
1379 isomgr_clients[c].emc_clk = clk_get_sys(
1380 isoclient_info[i].dev_name,
1381 isoclient_info[i].emc_clk_name);
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);
1388 isomgr_clients[c].emc_clk = NULL;
1395 isomgr_create_sysfs();
1398 #ifdef CONFIG_COMMON_CLK
1399 fs_initcall(isomgr_init);
1402 int tegra_isomgr_enable_test_mode(void)
1405 struct isomgr_client *cp = NULL;
1410 for (i = 0; i < TEGRA_ISO_CLIENT_COUNT; i++) {
1411 if (!client_valid[i])
1413 cp = &isomgr_clients[i];
1415 __tegra_isomgr_unregister(cp);
1416 if (atomic_read(&cp->kref.refcount))
1421 EXPORT_SYMBOL(tegra_isomgr_enable_test_mode);
1423 tegra_isomgr_handle test_tegra_isomgr_register(enum tegra_iso_client client,
1424 u32 dedicated_bw, /* KB/sec */
1425 tegra_isomgr_renegotiate renegotiate,
1428 return __tegra_isomgr_register(client, dedicated_bw, renegotiate, priv);
1430 EXPORT_SYMBOL(test_tegra_isomgr_register);
1432 void test_tegra_isomgr_unregister(tegra_isomgr_handle handle)
1434 return __tegra_isomgr_unregister(handle);
1436 EXPORT_SYMBOL(test_tegra_isomgr_unregister);
1438 u32 test_tegra_isomgr_reserve(tegra_isomgr_handle handle,
1439 u32 bw, /* KB/sec */
1442 return __tegra_isomgr_reserve(handle, bw, lt);
1444 EXPORT_SYMBOL(test_tegra_isomgr_reserve);
1446 u32 test_tegra_isomgr_realize(tegra_isomgr_handle handle)
1448 return __tegra_isomgr_realize(handle);
1450 EXPORT_SYMBOL(test_tegra_isomgr_realize);
1452 int test_tegra_isomgr_set_margin(enum tegra_iso_client client,
1455 return __tegra_isomgr_set_margin(client, bw, wait);
1457 EXPORT_SYMBOL(test_tegra_isomgr_set_margin);
1459 int test_tegra_isomgr_get_imp_time(enum tegra_iso_client client, u32 bw)
1461 return __tegra_isomgr_get_imp_time(client, bw);
1463 EXPORT_SYMBOL(test_tegra_isomgr_get_imp_time);
1465 u32 test_tegra_isomgr_get_available_iso_bw(void)
1467 return __tegra_isomgr_get_available_iso_bw();
1469 EXPORT_SYMBOL(test_tegra_isomgr_get_available_iso_bw);
1471 u32 test_tegra_isomgr_get_total_iso_bw(void)
1473 return __tegra_isomgr_get_total_iso_bw();
1475 EXPORT_SYMBOL(test_tegra_isomgr_get_total_iso_bw);