summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Payne <spayne@nvidia.com>2015-05-18 14:58:47 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-07-05 12:57:53 -0400
commitd15333eb77f0267a970de3f2649c9559be9b7f88 (patch)
tree276ca653af5ebaed7466a407b4ead2c416218e16
parent0e68c69116f97a4d4b96bba0906ca54ff457feac (diff)
video: tegra: host: move pod_scaling.c
move pod_scaling.c from nvhost to devfreq bug 1645757 Change-Id: I0e905bf7e14aa264c4235ddfa94536acd5e4c008 Signed-off-by: Sam Payne <spayne@nvidia.com> Reviewed-on: http://git-master/r/743942 Reviewed-on: http://git-master/r/756665 (cherry picked from linux-4.9 commit 80a8f5a341351c3973aee12fe1615785bcf8d6ee) Reviewed-on: https://git-master.nvidia.com/r/1770133 Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Timo Alho <talho@nvidia.com> Tested-by: Timo Alho <talho@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/devfreq/governor_pod_scaling.c1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/drivers/devfreq/governor_pod_scaling.c b/drivers/devfreq/governor_pod_scaling.c
new file mode 100644
index 000000000..59d90dbb0
--- /dev/null
+++ b/drivers/devfreq/governor_pod_scaling.c
@@ -0,0 +1,1033 @@
1/*
2 * drivers/video/tegra/host/gr3d/pod_scaling.c
3 *
4 * Tegra Graphics Host 3D clock scaling
5 *
6 * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/*
22 * Power-on-demand clock scaling for nvhost devices
23 *
24 * devfreq calls nvhost_pod_estimate_freq() for estimating the new
25 * frequency for the device. The clocking is done using two properties:
26 *
27 * (1) Usually the governor receives actively throughput hints that indicate
28 * whether scaling up or down is required.
29 * (2) The load of the device is estimated using the busy times from the
30 * device profile. This information indicates if the device frequency
31 * should be altered.
32 *
33 */
34
35#include <linux/devfreq.h>
36#include <linux/debugfs.h>
37#include <linux/types.h>
38#include <linux/clk.h>
39#include <linux/export.h>
40#include <linux/slab.h>
41#include <linux/clk/tegra.h>
42#include <linux/tegra-soc.h>
43
44#include <linux/notifier.h>
45#include <linux/tegra-throughput.h>
46
47#include <linux/notifier.h>
48#include <linux/tegra-throughput.h>
49
50#define CREATE_TRACE_POINTS
51#include <trace/events/nvhost_podgov.h>
52
53#include <governor.h>
54
55#include <linux/platform_device.h>
56#include <linux/pm_runtime.h>
57
58#define GET_TARGET_FREQ_DONTSCALE 1
59
60/* time frame for load and hint tracking - when events come in at a larger
61 * interval, this probably indicates the current estimates are stale
62 */
63#define GR3D_TIMEFRAME 1000000 /* 1 sec */
64
65/* the number of frames to use in the running average of load estimates and
66 * throughput hints. Choosing 6 frames targets a window of about 100 msec.
67 * Large flucutuations in frame times require a window that's large enough to
68 * prevent spiky scaling behavior, which in turn exacerbates frame rate
69 * instability.
70 */
71
72static void podgov_enable(struct devfreq *df, int enable);
73static void podgov_set_user_ctl(struct devfreq *df, int enable);
74
75static struct devfreq_governor nvhost_podgov;
76
77/*******************************************************************************
78 * podgov_info_rec - gr3d scaling governor specific parameters
79 ******************************************************************************/
80
81struct podgov_info_rec {
82
83 int enable;
84 int init;
85
86 ktime_t last_throughput_hint;
87 ktime_t last_scale;
88
89 struct delayed_work idle_timer;
90
91 unsigned int p_slowdown_delay;
92 unsigned int p_block_window;
93 unsigned int p_use_throughput_hint;
94 unsigned int p_hint_lo_limit;
95 unsigned int p_hint_hi_limit;
96 unsigned int p_scaleup_limit;
97 unsigned int p_scaledown_limit;
98 unsigned int p_smooth;
99 int p_damp;
100 int p_load_max;
101 int p_load_target;
102 int p_bias;
103 unsigned int p_user;
104 unsigned int p_freq_request;
105
106 long idle;
107
108 int adjustment_type;
109 unsigned long adjustment_frequency;
110
111 int last_event_type;
112
113 struct devfreq *power_manager;
114 struct dentry *debugdir;
115
116 unsigned long *freqlist;
117 int freq_count;
118
119 unsigned int idle_avg;
120 int freq_avg;
121 unsigned int hint_avg;
122 int block;
123 struct kobj_attribute enable_3d_scaling_attr;
124 struct kobj_attribute user_attr;
125 struct kobj_attribute freq_request_attr;
126
127 struct notifier_block throughput_hint_notifier;
128};
129
130/*******************************************************************************
131 * Adjustment type is used to tell the source that requested frequency re-
132 * estimation. Type ADJUSTMENT_LOCAL indicates that the re-estimation was
133 * initiated by the governor itself. This happens when one of the worker
134 * threads want to adjust the frequency.
135 *
136 * ADJUSTMENT_DEVICE_REQ (default value) indicates that the adjustment was
137 * initiated by a device event.
138 ******************************************************************************/
139
140enum podgov_adjustment_type {
141 ADJUSTMENT_LOCAL = 0,
142 ADJUSTMENT_DEVICE_REQ = 1
143};
144
145
146static void stop_podgov_workers(struct podgov_info_rec *podgov)
147{
148 /* idle_timer can rearm itself */
149 do {
150 cancel_delayed_work_sync(&podgov->idle_timer);
151 } while (delayed_work_pending(&podgov->idle_timer));
152}
153
154/*******************************************************************************
155 * scaling_limit(df, freq)
156 *
157 * Limit the given frequency
158 ******************************************************************************/
159
160static void scaling_limit(struct devfreq *df, unsigned long *freq)
161{
162 if (*freq < df->min_freq)
163 *freq = df->min_freq;
164 else if (*freq > df->max_freq)
165 *freq = df->max_freq;
166}
167
168/*******************************************************************************
169 * nvhost_pod_suspend(dev)
170 *
171 * Prepare the device for suspend
172 ******************************************************************************/
173
174static void nvhost_pod_suspend(struct devfreq *df)
175{
176 struct podgov_info_rec *podgov;
177
178 mutex_lock(&df->lock);
179
180 podgov = df->data;
181 if (!(df->governor == &nvhost_podgov &&
182 podgov && podgov->enable)) {
183 mutex_unlock(&df->lock);
184 return;
185 }
186 mutex_unlock(&df->lock);
187
188 stop_podgov_workers(podgov);
189}
190
191/*******************************************************************************
192 * podgov_enable(dev, enable)
193 *
194 * This function enables (enable=1) or disables (enable=0) the automatic scaling
195 * of the device. If the device is disabled, the device's clock is set to its
196 * maximum.
197 ******************************************************************************/
198
199static void podgov_enable(struct devfreq *df, int enable)
200{
201 struct device *dev = df->dev.parent;
202 struct podgov_info_rec *podgov;
203
204 /* make sure the device is alive before doing any scaling */
205 pm_runtime_get_noresume(dev);
206
207 mutex_lock(&df->lock);
208
209 podgov = df->data;
210
211 trace_podgov_enabled(df->dev.parent, enable);
212
213 /* bad configuration. quit. */
214 if (df->min_freq == df->max_freq)
215 goto exit_unlock;
216
217 /* store the enable information */
218 podgov->enable = enable;
219
220 /* skip local adjustment if we are enabling or the device is
221 * suspended */
222 if (enable || !pm_runtime_active(dev))
223 goto exit_unlock;
224
225 /* full speed */
226 podgov->adjustment_frequency = df->max_freq;
227 podgov->adjustment_type = ADJUSTMENT_LOCAL;
228 update_devfreq(df);
229
230 mutex_unlock(&df->lock);
231
232 pm_runtime_put(dev);
233
234 stop_podgov_workers(podgov);
235
236 return;
237
238exit_unlock:
239 mutex_unlock(&df->lock);
240 pm_runtime_put(dev);
241}
242
243/*****************************************************************************
244 * podgov_set_user_ctl(dev, user)
245 *
246 * This function enables or disables user control of the gpu. If user control
247 * is enabled, setting the freq_request controls the gpu frequency, and other
248 * gpu scaling mechanisms are disabled.
249 ******************************************************************************/
250
251static void podgov_set_user_ctl(struct devfreq *df, int user)
252{
253 struct device *dev = df->dev.parent;
254 struct podgov_info_rec *podgov;
255 int old_user;
256
257 /* make sure the device is alive before doing any scaling */
258 pm_runtime_get_noresume(dev);
259
260 mutex_lock(&df->lock);
261 podgov = df->data;
262
263 trace_podgov_set_user_ctl(df->dev.parent, user);
264
265 /* store the new user value */
266 old_user = podgov->p_user;
267 podgov->p_user = user;
268
269 /* skip scaling, if scaling (or the whole device) is turned off
270 * - or the scaling already was in user mode */
271 if (!pm_runtime_active(dev) || !podgov->enable ||
272 !(user && !old_user))
273 goto exit_unlock;
274
275 /* write request */
276 podgov->adjustment_frequency = podgov->p_freq_request;
277 podgov->adjustment_type = ADJUSTMENT_LOCAL;
278 update_devfreq(df);
279
280 mutex_unlock(&df->lock);
281 pm_runtime_put(dev);
282
283 stop_podgov_workers(podgov);
284
285 return;
286
287exit_unlock:
288 mutex_unlock(&df->lock);
289 pm_runtime_put(dev);
290}
291
292/*****************************************************************************
293 * podgov_set_freq_request(dev, user)
294 *
295 * Set the current freq request. If scaling is enabled, and podgov user space
296 * control is enabled, this will set the gpu frequency.
297 ******************************************************************************/
298
299static void podgov_set_freq_request(struct devfreq *df, int freq_request)
300{
301 struct device *dev = df->dev.parent;
302 struct podgov_info_rec *podgov;
303
304 /* make sure the device is alive before doing any scaling */
305 pm_runtime_get_noresume(dev);
306
307 mutex_lock(&df->lock);
308
309 podgov = df->data;
310
311 trace_podgov_set_freq_request(df->dev.parent, freq_request);
312
313 podgov->p_freq_request = freq_request;
314
315 /* update the request only if podgov is enabled, device is turned on
316 * and the scaling is in user mode */
317 if (podgov->enable && podgov->p_user &&
318 pm_runtime_active(dev)) {
319 podgov->adjustment_frequency = freq_request;
320 podgov->adjustment_type = ADJUSTMENT_LOCAL;
321 update_devfreq(df);
322 }
323
324 mutex_unlock(&df->lock);
325 pm_runtime_put(dev);
326}
327
328
329/*******************************************************************************
330 * freq = scaling_state_check(df, time)
331 *
332 * This handler is called to adjust the frequency of the device. The function
333 * returns the desired frequency for the clock. If there is no need to tune the
334 * clock immediately, 0 is returned.
335 ******************************************************************************/
336
337static unsigned long scaling_state_check(struct devfreq *df, ktime_t time)
338{
339 struct podgov_info_rec *podgov = df->data;
340 unsigned long dt;
341 long max_boost, load, damp, freq, boost, res;
342
343 dt = (unsigned long) ktime_us_delta(time, podgov->last_scale);
344 if (dt < podgov->p_block_window || df->previous_freq == 0)
345 return 0;
346
347 /* convert to mhz to avoid overflow */
348 freq = df->previous_freq / 1000000;
349 max_boost = (df->max_freq/3) / 1000000;
350
351 /* calculate and trace load */
352 load = 1000 - podgov->idle_avg;
353 trace_podgov_busy(df->dev.parent, load);
354 damp = podgov->p_damp;
355
356 if ((1000 - podgov->idle) > podgov->p_load_max) {
357 /* if too busy, scale up max/3, do not damp */
358 boost = max_boost;
359 damp = 10;
360
361 } else {
362 /* boost = bias * freq * (load - target)/target */
363 boost = (load - podgov->p_load_target);
364 boost *= (podgov->p_bias * freq);
365 boost /= (100 * podgov->p_load_target);
366
367 /* clamp to max boost */
368 boost = (boost < max_boost) ? boost : max_boost;
369 }
370
371 /* calculate new request */
372 res = freq + boost;
373
374 /* Maintain average request */
375 podgov->freq_avg = (podgov->freq_avg * podgov->p_smooth) + res;
376 podgov->freq_avg /= (podgov->p_smooth+1);
377
378 /* Applying damping to frequencies */
379 res = ((damp * res) + ((10 - damp)*podgov->freq_avg)) / 10;
380
381 /* Convert to hz, limit, and apply */
382 res = res * 1000000;
383 scaling_limit(df, &res);
384 trace_podgov_scaling_state_check(df->dev.parent,
385 df->previous_freq, res);
386 return res;
387}
388
389/*******************************************************************************
390 * freqlist_up(podgov, target, steps)
391 *
392 * This function determines the frequency that is "steps" frequency steps
393 * higher compared to the target frequency.
394 ******************************************************************************/
395
396static int freqlist_up(struct podgov_info_rec *podgov, unsigned long target,
397 int steps)
398{
399 int i, pos;
400
401 for (i = 0; i < podgov->freq_count; i++)
402 if (podgov->freqlist[i] >= target)
403 break;
404
405 pos = min(podgov->freq_count - 1, i + steps);
406 return podgov->freqlist[pos];
407}
408
409/*******************************************************************************
410 * podgov_idle_handler(work)
411 *
412 * This handler is called after the device has been idle long enough. This
413 * handler forms a (positive) feedback loop by notifying idle to the device.
414 ******************************************************************************/
415
416static void podgov_idle_handler(struct work_struct *work)
417{
418 struct delayed_work *idle_timer =
419 container_of(work, struct delayed_work, work);
420 struct podgov_info_rec *podgov =
421 container_of(idle_timer, struct podgov_info_rec, idle_timer);
422 struct devfreq *df = podgov->power_manager;
423
424 mutex_lock(&df->lock);
425
426 if (!podgov->enable) {
427 mutex_unlock(&df->lock);
428 return;
429 }
430
431 if (!podgov->last_event_type &&
432 df->previous_freq > df->min_freq &&
433 podgov->p_user == false)
434 update_devfreq(df);
435
436 mutex_unlock(&df->lock);
437}
438
439#ifdef CONFIG_TEGRA_THROUGHPUT
440/*******************************************************************************
441 * freqlist_down(podgov, target, steps)
442 *
443 * This function determines the frequency that is "steps" frequency steps
444 * lower compared to the target frequency.
445 ******************************************************************************/
446
447static int freqlist_down(struct podgov_info_rec *podgov, unsigned long target,
448 int steps)
449{
450 int i, pos;
451
452 for (i = podgov->freq_count - 1; i >= 0; i--)
453 if (podgov->freqlist[i] <= target)
454 break;
455
456 pos = max(0, i - steps);
457 return podgov->freqlist[pos];
458}
459
460/*******************************************************************************
461 * nvhost_scale_emc_set_throughput_hint(hint)
462 *
463 * This function can be used to request scaling up or down based on the
464 * required throughput
465 ******************************************************************************/
466
467static int nvhost_scale_emc_set_throughput_hint(struct notifier_block *nb,
468 unsigned long action, void *data)
469{
470 struct podgov_info_rec *podgov =
471 container_of(nb, struct podgov_info_rec,
472 throughput_hint_notifier);
473 struct devfreq *df = podgov->power_manager;
474 struct device *dev = df->dev.parent;
475 int hint = tegra_throughput_get_hint();
476 long idle;
477 unsigned long curr, target;
478 int avg_idle, avg_hint, scale_score;
479 unsigned int smooth;
480
481 /* make sure the device is alive before doing any scaling */
482 pm_runtime_get_noresume(dev);
483 if (!pm_runtime_active(dev)) {
484 pm_runtime_put(dev);
485 return 0;
486 }
487
488 mutex_lock(&df->lock);
489
490 podgov->block--;
491
492 if (!podgov->enable ||
493 !podgov->p_use_throughput_hint ||
494 podgov->block > 0)
495 goto exit_unlock;
496
497 trace_podgov_hint(df->dev.parent, podgov->idle, hint);
498 podgov->last_throughput_hint = ktime_get();
499
500 curr = df->previous_freq;
501 idle = podgov->idle;
502 avg_idle = podgov->idle_avg;
503 smooth = podgov->p_smooth;
504
505 /* compute averages usings exponential-moving-average */
506 avg_hint = ((smooth*podgov->hint_avg + hint)/(smooth+1));
507 podgov->hint_avg = avg_hint;
508
509 /* set the target using avg_hint and avg_idle */
510 target = curr;
511 if (avg_hint < podgov->p_hint_lo_limit) {
512 target = freqlist_up(podgov, curr, 1);
513 } else {
514 scale_score = avg_idle + avg_hint;
515 if (scale_score > podgov->p_scaledown_limit)
516 target = freqlist_down(podgov, curr, 1);
517 else if (scale_score < podgov->p_scaleup_limit
518 && hint < podgov->p_hint_hi_limit)
519 target = freqlist_up(podgov, curr, 1);
520 }
521
522 /* clamp and apply target */
523 scaling_limit(df, &target);
524 if (target != curr) {
525 podgov->block = podgov->p_smooth;
526 trace_podgov_do_scale(df->dev.parent,
527 df->previous_freq, target);
528 podgov->adjustment_frequency = target;
529 podgov->adjustment_type = ADJUSTMENT_LOCAL;
530 update_devfreq(df);
531 }
532
533 trace_podgov_print_target(df->dev.parent, idle, avg_idle,
534 curr / 1000000, target, hint, avg_hint);
535
536exit_unlock:
537 mutex_unlock(&df->lock);
538 pm_runtime_put(dev);
539 return NOTIFY_OK;
540}
541#endif
542
543/*******************************************************************************
544 * debugfs interface for controlling 3d clock scaling on the fly
545 ******************************************************************************/
546
547#ifdef CONFIG_DEBUG_FS
548
549static void nvhost_scale_emc_debug_init(struct devfreq *df)
550{
551 struct podgov_info_rec *podgov = df->data;
552 struct dentry *f;
553 char dirname[128];
554
555 snprintf(dirname, sizeof(dirname), "%s_scaling",
556 to_platform_device(df->dev.parent)->name);
557
558 if (!podgov)
559 return;
560
561 podgov->debugdir = debugfs_create_dir(dirname, NULL);
562 if (!podgov->debugdir) {
563 pr_err("podgov: can\'t create debugfs directory\n");
564 return;
565 }
566
567#define CREATE_PODGOV_FILE(fname) \
568 do {\
569 f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, \
570 podgov->debugdir, &podgov->p_##fname); \
571 if (NULL == f) { \
572 pr_err("podgov: can\'t create file " #fname "\n"); \
573 return; \
574 } \
575 } while (0)
576
577 CREATE_PODGOV_FILE(block_window);
578 CREATE_PODGOV_FILE(load_max);
579 CREATE_PODGOV_FILE(load_target);
580 CREATE_PODGOV_FILE(bias);
581 CREATE_PODGOV_FILE(damp);
582 CREATE_PODGOV_FILE(use_throughput_hint);
583 CREATE_PODGOV_FILE(hint_hi_limit);
584 CREATE_PODGOV_FILE(hint_lo_limit);
585 CREATE_PODGOV_FILE(scaleup_limit);
586 CREATE_PODGOV_FILE(scaledown_limit);
587 CREATE_PODGOV_FILE(smooth);
588 CREATE_PODGOV_FILE(slowdown_delay);
589#undef CREATE_PODGOV_FILE
590}
591
592static void nvhost_scale_emc_debug_deinit(struct devfreq *df)
593{
594 struct podgov_info_rec *podgov = df->data;
595
596 debugfs_remove_recursive(podgov->debugdir);
597}
598
599#else
600static void nvhost_scale_emc_debug_init(struct devfreq *df)
601{
602 (void)df;
603}
604
605static void nvhost_scale_emc_debug_deinit(struct devfreq *df)
606{
607 (void)df;
608}
609#endif
610
611/*******************************************************************************
612 * sysfs interface for enabling/disabling 3d scaling
613 ******************************************************************************/
614
615static ssize_t enable_3d_scaling_show(struct kobject *kobj,
616 struct kobj_attribute *attr,
617 char *buf)
618{
619 struct podgov_info_rec *podgov = container_of(attr,
620 struct podgov_info_rec,
621 enable_3d_scaling_attr);
622 ssize_t res;
623
624 res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->enable);
625
626 return res;
627}
628
629static ssize_t enable_3d_scaling_store(struct kobject *kobj,
630 struct kobj_attribute *attr,
631 const char *buf, size_t count)
632{
633 struct podgov_info_rec *podgov = container_of(attr,
634 struct podgov_info_rec,
635 enable_3d_scaling_attr);
636 unsigned long val = 0;
637
638 if (kstrtoul(buf, 10, &val) < 0)
639 return -EINVAL;
640
641 podgov_enable(podgov->power_manager, val);
642
643 return count;
644}
645
646/*******************************************************************************
647 * sysfs interface for user space control
648 * user = [0,1] disables / enabled user space control
649 * freq_request is the sysfs node user space writes frequency requests to
650 ******************************************************************************/
651
652static ssize_t user_show(struct kobject *kobj,
653 struct kobj_attribute *attr,
654 char *buf)
655{
656 struct podgov_info_rec *podgov =
657 container_of(attr, struct podgov_info_rec, user_attr);
658 ssize_t res;
659
660 res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_user);
661
662 return res;
663}
664
665static ssize_t user_store(struct kobject *kobj,
666 struct kobj_attribute *attr,
667 const char *buf, size_t count)
668{
669 struct podgov_info_rec *podgov =
670 container_of(attr, struct podgov_info_rec, user_attr);
671 unsigned long val = 0;
672
673 if (kstrtoul(buf, 10, &val) < 0)
674 return -EINVAL;
675
676 podgov_set_user_ctl(podgov->power_manager, val);
677
678 return count;
679}
680
681static ssize_t freq_request_show(struct kobject *kobj,
682 struct kobj_attribute *attr,
683 char *buf)
684{
685 struct podgov_info_rec *podgov =
686 container_of(attr, struct podgov_info_rec, freq_request_attr);
687 ssize_t res;
688
689 res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_freq_request);
690
691 return res;
692}
693
694static ssize_t freq_request_store(struct kobject *kobj,
695 struct kobj_attribute *attr,
696 const char *buf, size_t count)
697{
698 struct podgov_info_rec *podgov =
699 container_of(attr, struct podgov_info_rec, freq_request_attr);
700 unsigned long val = 0;
701
702 if (kstrtoul(buf, 10, &val) < 0)
703 return -EINVAL;
704
705 podgov_set_freq_request(podgov->power_manager, val);
706
707 return count;
708}
709
710/*******************************************************************************
711 * nvhost_pod_estimate_freq(df, freq)
712 *
713 * This function is called for re-estimating the frequency. The function is
714 * called in three conditions:
715 *
716 * (1) Internal request to change the frequency. In this case a new clock
717 * target is immediately set for the device.
718 * (2) Call from the client (something has happened and re-estimation
719 * is required).
720 * (3) Some other reason (i.e. periodic call)
721 *
722 ******************************************************************************/
723
724static int nvhost_pod_estimate_freq(struct devfreq *df,
725 unsigned long *freq)
726{
727 struct podgov_info_rec *podgov = df->data;
728 struct devfreq_dev_status dev_stat;
729 int stat;
730 ktime_t now;
731
732 stat = df->profile->get_dev_status(df->dev.parent, &dev_stat);
733 if (stat < 0)
734 return stat;
735
736 /* Ensure maximal clock when scaling is disabled */
737 if (!podgov->enable) {
738 *freq = df->max_freq;
739 return 0;
740 }
741
742 if (podgov->p_user) {
743 *freq = podgov->p_freq_request;
744 return 0;
745 }
746
747 if (dev_stat.total_time == 0) {
748 *freq = dev_stat.current_frequency;
749 return 0;
750 }
751
752 stat = 0;
753 now = ktime_get();
754
755 /* Local adjustments (i.e. requests from kernel threads) are
756 * handled here */
757
758 if (podgov->adjustment_type == ADJUSTMENT_LOCAL) {
759
760 podgov->adjustment_type = ADJUSTMENT_DEVICE_REQ;
761
762 /* Do not do unnecessary scaling */
763 scaling_limit(df, &podgov->adjustment_frequency);
764
765 /* Round the frequency and check if we're already there */
766 if (freqlist_up(podgov, podgov->adjustment_frequency, 0) ==
767 dev_stat.current_frequency)
768 return GET_TARGET_FREQ_DONTSCALE;
769
770 trace_podgov_estimate_freq(df->dev.parent,
771 df->previous_freq,
772 podgov->adjustment_frequency);
773
774 *freq = podgov->adjustment_frequency;
775 return 0;
776 }
777
778 *freq = dev_stat.current_frequency;
779
780 /* Sustain local variables */
781 podgov->last_event_type = dev_stat.busy;
782 podgov->idle = 1000 * (dev_stat.total_time - dev_stat.busy_time);
783 podgov->idle = podgov->idle / dev_stat.total_time;
784 podgov->idle_avg = (podgov->p_smooth * podgov->idle_avg) +
785 podgov->idle;
786 podgov->idle_avg = podgov->idle_avg / (podgov->p_smooth + 1);
787
788 /* if throughput hint enabled, and last hint is recent enough, return */
789 if (podgov->p_use_throughput_hint &&
790 ktime_us_delta(now, podgov->last_throughput_hint) < 1000000)
791 return GET_TARGET_FREQ_DONTSCALE;
792
793 if (dev_stat.busy) {
794 cancel_delayed_work(&podgov->idle_timer);
795 *freq = scaling_state_check(df, now);
796 } else {
797 /* Launch a work to slowdown the gpu */
798 *freq = scaling_state_check(df, now);
799 schedule_delayed_work(&podgov->idle_timer,
800 msecs_to_jiffies(podgov->p_slowdown_delay));
801 }
802
803 if (!(*freq) ||
804 (freqlist_up(podgov, *freq, 0) == dev_stat.current_frequency))
805 return GET_TARGET_FREQ_DONTSCALE;
806
807 podgov->last_scale = now;
808
809 trace_podgov_estimate_freq(df->dev.parent, df->previous_freq, *freq);
810
811
812 return 0;
813}
814
815/*******************************************************************************
816 * nvhost_pod_init(struct devfreq *df)
817 *
818 * Governor initialisation.
819 ******************************************************************************/
820
821static int nvhost_pod_init(struct devfreq *df)
822{
823 struct podgov_info_rec *podgov;
824 struct platform_device *d = to_platform_device(df->dev.parent);
825 ktime_t now = ktime_get();
826 enum tegra_chipid cid = tegra_get_chipid();
827
828 struct devfreq_dev_status dev_stat;
829 int stat = 0;
830
831 struct kobj_attribute *attr = NULL;
832
833 podgov = kzalloc(sizeof(struct podgov_info_rec), GFP_KERNEL);
834 if (!podgov)
835 goto err_alloc_podgov;
836 df->data = (void *)podgov;
837
838 /* Initialise workers */
839 INIT_DELAYED_WORK(&podgov->idle_timer, podgov_idle_handler);
840
841 /* Set scaling parameter defaults */
842 podgov->enable = 1;
843 podgov->block = 0;
844 podgov->p_use_throughput_hint = 1;
845
846 if (!strcmp(d->name, "vic03.0")) {
847 podgov->p_load_max = 990;
848 podgov->p_load_target = 250;
849 podgov->p_bias = 80;
850 podgov->p_hint_lo_limit = 500;
851 podgov->p_hint_hi_limit = 997;
852 podgov->p_scaleup_limit = 1100;
853 podgov->p_scaledown_limit = 1300;
854 podgov->p_smooth = 60;
855 podgov->p_damp = 2;
856 } else {
857 switch (cid) {
858 case TEGRA_CHIPID_TEGRA14:
859 case TEGRA_CHIPID_TEGRA11:
860 case TEGRA_CHIPID_TEGRA12:
861 case TEGRA_CHIPID_TEGRA13:
862 case TEGRA_CHIPID_TEGRA21:
863 podgov->p_load_max = 900;
864 podgov->p_load_target = 700;
865 podgov->p_bias = 80;
866 podgov->p_hint_lo_limit = 500;
867 podgov->p_hint_hi_limit = 997;
868 podgov->p_scaleup_limit = 1100;
869 podgov->p_scaledown_limit = 1300;
870 podgov->p_smooth = 10;
871 podgov->p_damp = 7;
872 podgov->p_use_throughput_hint = 0;
873 break;
874 default:
875 pr_err("%s: un-supported chip id\n", __func__);
876 goto err_unsupported_chip_id;
877 break;
878 }
879 }
880
881 podgov->p_slowdown_delay = 10;
882 podgov->p_block_window = 50000;
883 podgov->adjustment_type = ADJUSTMENT_DEVICE_REQ;
884 podgov->p_user = 0;
885
886 /* Reset clock counters */
887 podgov->last_throughput_hint = now;
888 podgov->last_scale = now;
889
890 podgov->power_manager = df;
891
892 /* Get the current status of the device */
893 stat = df->profile->get_dev_status(df->dev.parent, &dev_stat);
894
895 attr = &podgov->enable_3d_scaling_attr;
896 attr->attr.name = "enable_3d_scaling";
897 attr->attr.mode = S_IWUSR | S_IRUGO;
898 attr->show = enable_3d_scaling_show;
899 attr->store = enable_3d_scaling_store;
900 sysfs_attr_init(&attr->attr);
901 if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
902 goto err_create_enable_sysfs_entry;
903
904 attr = &podgov->freq_request_attr;
905 attr->attr.name = "freq_request";
906 attr->attr.mode = S_IWUSR | S_IRUGO;
907 attr->show = freq_request_show;
908 attr->store = freq_request_store;
909 sysfs_attr_init(&attr->attr);
910 if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
911 goto err_create_request_sysfs_entry;
912
913 attr = &podgov->user_attr;
914 attr->attr.name = "user";
915 attr->attr.mode = S_IWUSR | S_IRUGO;
916 attr->show = user_show;
917 attr->store = user_store;
918 sysfs_attr_init(&attr->attr);
919 if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
920 goto err_create_user_sysfs_entry;
921
922 podgov->freq_count = df->profile->max_state;
923 podgov->freqlist = df->profile->freq_table;
924 if (!podgov->freq_count || !podgov->freqlist)
925 goto err_get_freqs;
926
927 /* store the limits */
928 df->min_freq = podgov->freqlist[0];
929 df->max_freq = podgov->freqlist[podgov->freq_count - 1];
930 podgov->p_freq_request = df->max_freq;
931
932 podgov->idle_avg = 0;
933 podgov->freq_avg = 0;
934 podgov->hint_avg = 0;
935
936 nvhost_scale_emc_debug_init(df);
937
938 /* register the governor to throughput hint notifier chain */
939#ifdef CONFIG_TEGRA_THROUGHPUT
940 podgov->throughput_hint_notifier.notifier_call =
941 &nvhost_scale_emc_set_throughput_hint;
942 blocking_notifier_chain_register(&throughput_notifier_list,
943 &podgov->throughput_hint_notifier);
944#endif
945
946 return 0;
947
948err_get_freqs:
949 sysfs_remove_file(&df->dev.parent->kobj, &podgov->user_attr.attr);
950err_create_user_sysfs_entry:
951 sysfs_remove_file(&df->dev.parent->kobj,
952 &podgov->freq_request_attr.attr);
953err_create_request_sysfs_entry:
954 sysfs_remove_file(&df->dev.parent->kobj,
955 &podgov->enable_3d_scaling_attr.attr);
956err_create_enable_sysfs_entry:
957 dev_err(&d->dev, "failed to create sysfs attributes");
958err_unsupported_chip_id:
959 kfree(podgov);
960err_alloc_podgov:
961 return -ENOMEM;
962}
963
964/*******************************************************************************
965 * nvhost_pod_exit(struct devfreq *df)
966 *
967 * Clean up governor data structures
968 ******************************************************************************/
969
970static void nvhost_pod_exit(struct devfreq *df)
971{
972 struct podgov_info_rec *podgov = df->data;
973
974#ifdef CONFIG_TEGRA_THROUGHPUT
975 blocking_notifier_chain_unregister(&throughput_notifier_list,
976 &podgov->throughput_hint_notifier);
977#endif
978 cancel_delayed_work(&podgov->idle_timer);
979
980 sysfs_remove_file(&df->dev.parent->kobj, &podgov->user_attr.attr);
981 sysfs_remove_file(&df->dev.parent->kobj,
982 &podgov->freq_request_attr.attr);
983 sysfs_remove_file(&df->dev.parent->kobj,
984 &podgov->enable_3d_scaling_attr.attr);
985
986 nvhost_scale_emc_debug_deinit(df);
987
988 kfree(podgov);
989}
990
991static int nvhost_pod_event_handler(struct devfreq *df,
992 unsigned int event, void *data)
993{
994 int ret = 0;
995
996 switch (event) {
997 case DEVFREQ_GOV_START:
998 ret = nvhost_pod_init(df);
999 break;
1000 case DEVFREQ_GOV_STOP:
1001 nvhost_pod_exit(df);
1002 break;
1003 case DEVFREQ_GOV_SUSPEND:
1004 nvhost_pod_suspend(df);
1005 break;
1006 default:
1007 break;
1008 }
1009
1010 return ret;
1011}
1012
1013static struct devfreq_governor nvhost_podgov = {
1014 .name = "nvhost_podgov",
1015 .get_target_freq = nvhost_pod_estimate_freq,
1016 .event_handler = nvhost_pod_event_handler,
1017};
1018
1019
1020static int __init podgov_init(void)
1021{
1022 return devfreq_add_governor(&nvhost_podgov);
1023}
1024
1025static void __exit podgov_exit(void)
1026{
1027 devfreq_remove_governor(&nvhost_podgov);
1028}
1029
1030/* governor must be registered before initialising client devices */
1031rootfs_initcall(podgov_init);
1032module_exit(podgov_exit);
1033