diff options
author | Ilan Aelion <iaelion@nvidia.com> | 2011-10-25 17:33:53 -0600 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2011-12-08 18:07:52 +0530 |
commit | 869d10ac35512cc411382134de89bce95251f11c (patch) | |
tree | 12731c29aa79eb29d45090bc3f3e53b4f2a22789 /drivers/video/tegra/host/t30 | |
parent | 08580dde93cd93de07f8124c59fc3c8300f3e4ed (diff) |
video: tegra: host: adjusted 3d frequency scaling
count scale up / down hints to adjust scaling parameters.
Reviewed-on: http://git-master/r/#change,60338
(cherry picked from commit 093d16d905e7bd299c6fb1d627b6e8317ed8c714)
Change-Id: Ie4716570a2bfcb82fd595932eef94102364fb18a
Reviewed-on: http://git-master/r/63719
Tested-by: Ilan Aelion <iaelion@nvidia.com>
Reviewed-by: Luke Huang <lhuang@nvidia.com>
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/host/t30')
-rw-r--r-- | drivers/video/tegra/host/t30/scale3d.c | 160 |
1 files changed, 142 insertions, 18 deletions
diff --git a/drivers/video/tegra/host/t30/scale3d.c b/drivers/video/tegra/host/t30/scale3d.c index 734346478c43..eb02f34385fc 100644 --- a/drivers/video/tegra/host/t30/scale3d.c +++ b/drivers/video/tegra/host/t30/scale3d.c @@ -66,8 +66,13 @@ struct scale3d_info_rec { ktime_t fast_frame; ktime_t last_idle; ktime_t last_short_term_idle; - ktime_t last_busy; int is_idle; + ktime_t last_tweak; + ktime_t last_down; + int fast_up_count; + int slow_down_count; + int is_scaled; + int fast_responses; unsigned long idle_total; unsigned long idle_short_term_total; unsigned long max_rate_3d; @@ -76,9 +81,14 @@ struct scale3d_info_rec { struct delayed_work idle_timer; unsigned int scale; unsigned int p_period; + unsigned int period; unsigned int p_idle_min; + unsigned int idle_min; unsigned int p_idle_max; + unsigned int idle_max; unsigned int p_fast_response; + unsigned int fast_response; + unsigned int p_adjust; unsigned int p_verbosity; struct clk *clk_3d; struct clk *clk_3d2; @@ -171,23 +181,133 @@ static void reset_scaling_counters(ktime_t time) scale3d.idle_short_term_total = 0; scale3d.last_idle = time; scale3d.last_short_term_idle = time; - scale3d.last_busy = time; scale3d.idle_frame = time; } +/* scaling_adjust - use scale up / scale down hint counts to adjust scaling + * parameters. + * + * hint_ratio is 100 x the ratio of scale up to scale down hints. Three cases + * are distinguished: + * + * hint_ratio < HINT_RATIO_MIN - set parameters to maximize scaling effect + * hint_ratio > HINT_RATIO_MAX - set parameters to minimize scaling effect + * hint_ratio between limits - scale parameters linearly + * + * the parameters adjusted are + * + * * fast_response time + * * period - time for scaling down estimate + * * idle_min percentage + * * idle_max percentage + */ +#define SCALING_ADJUST_PERIOD 1000000 +#define HINT_RATIO_MAX 400 +#define HINT_RATIO_MIN 100 +#define HINT_RATIO_MID ((HINT_RATIO_MAX + HINT_RATIO_MIN) / 2) +#define HINT_RATIO_DIFF (HINT_RATIO_MAX - HINT_RATIO_MIN) + +static void scaling_adjust(ktime_t time) +{ + long hint_ratio; + long fast_response_adjustment; + long period_adjustment; + int idle_min_adjustment; + int idle_max_adjustment; + unsigned long dt; + + dt = (unsigned long) ktime_us_delta(time, scale3d.last_tweak); + if (dt < SCALING_ADJUST_PERIOD) + return; + + hint_ratio = (100 * (scale3d.fast_up_count + 1)) / + (scale3d.slow_down_count + 1); + + if (hint_ratio > HINT_RATIO_MAX) { + fast_response_adjustment = -((int) scale3d.p_fast_response) / 4; + period_adjustment = scale3d.p_period / 2; + idle_min_adjustment = scale3d.p_idle_min; + idle_max_adjustment = scale3d.p_idle_max; + } else if (hint_ratio < HINT_RATIO_MIN) { + fast_response_adjustment = scale3d.p_fast_response / 2; + period_adjustment = -((int) scale3d.p_period) / 4; + idle_min_adjustment = -((int) scale3d.p_idle_min) / 2; + idle_max_adjustment = -((int) scale3d.p_idle_max) / 2; + } else { + int diff; + int factor; + + diff = HINT_RATIO_MID - hint_ratio; + if (diff < 0) + factor = -diff * 2; + else { + factor = -diff; + diff *= 2; + } + + fast_response_adjustment = diff * + (scale3d.p_fast_response / (HINT_RATIO_DIFF * 2)); + period_adjustment = + diff * (scale3d.p_period / HINT_RATIO_DIFF); + idle_min_adjustment = + (factor * (int) scale3d.p_idle_min) / HINT_RATIO_DIFF; + idle_max_adjustment = + (factor * (int) scale3d.p_idle_max) / HINT_RATIO_DIFF; + } + + scale3d.fast_response = + scale3d.p_fast_response + fast_response_adjustment; + scale3d.period = scale3d.p_period + period_adjustment; + scale3d.idle_min = scale3d.p_idle_min + idle_min_adjustment; + scale3d.idle_max = scale3d.p_idle_max + idle_max_adjustment; + + if (scale3d.p_verbosity >= 10) + pr_info("scale3d stats: + %d - %d (/ %d) f %u p %u min %u max %u\n", + scale3d.fast_up_count, scale3d.slow_down_count, + scale3d.fast_responses, scale3d.fast_response, + scale3d.period, scale3d.idle_min, scale3d.idle_max); + + scale3d.fast_up_count = 0; + scale3d.slow_down_count = 0; + scale3d.fast_responses = 0; + scale3d.last_down = time; + scale3d.last_tweak = time; +} + +#undef SCALING_ADJUST_PERIOD +#undef HINT_RATIO_MAX +#undef HINT_RATIO_MIN +#undef HINT_RATIO_MID +#undef HINT_RATIO_DIFF + static void scaling_state_check(ktime_t time) { unsigned long dt; + /* adjustment: set scale parameters (fast_response, period) +/- 25% + * based on ratio of scale up to scale down hints + */ + if (scale3d.p_adjust) + scaling_adjust(time); + else { + scale3d.fast_response = scale3d.p_fast_response; + scale3d.period = scale3d.p_period; + scale3d.idle_min = scale3d.p_idle_min; + scale3d.idle_max = scale3d.p_idle_max; + } + /* check for load peaks */ dt = (unsigned long) ktime_us_delta(time, scale3d.fast_frame); - if (dt > scale3d.p_fast_response) { + if (dt > scale3d.fast_response) { unsigned long idleness = (scale3d.idle_short_term_total * 100) / dt; + scale3d.fast_responses++; scale3d.fast_frame = time; /* if too busy, scale up */ - if (idleness < scale3d.p_idle_min) { - if (scale3d.p_verbosity > 5) + if (idleness < scale3d.idle_min) { + scale3d.is_scaled = 0; + scale3d.fast_up_count++; + if (scale3d.p_verbosity >= 5) pr_info("scale3d: %ld%% busy\n", 100 - idleness); @@ -200,21 +320,24 @@ static void scaling_state_check(ktime_t time) } dt = (unsigned long) ktime_us_delta(time, scale3d.idle_frame); - if (dt > scale3d.p_period) { + if (dt > scale3d.period) { unsigned long idleness = (scale3d.idle_total * 100) / dt; - if (scale3d.p_verbosity > 5) + if (scale3d.p_verbosity >= 5) pr_info("scale3d: idle %lu, ~%lu%%\n", scale3d.idle_total, idleness); - if (idleness > scale3d.p_idle_max) { + if (idleness > scale3d.idle_max) { + if (!scale3d.is_scaled) { + scale3d.is_scaled = 1; + scale3d.last_down = time; + } + scale3d.slow_down_count++; /* if idle time is high, clock down */ - scale3d.scale = 100 - (idleness - scale3d.p_idle_min); + scale3d.scale = 100 - (idleness - scale3d.idle_min); schedule_work(&scale3d.work); - } else if (idleness < scale3d.p_idle_min) { - /* if idle time is low, clock up */ - reset_3d_clocks(); } + reset_scaling_counters(time); } } @@ -246,7 +369,7 @@ void nvhost_scale3d_notify_idle(struct nvhost_module *mod) /* delay idle_max % of 2 * fast_response time (given in microseconds) */ schedule_delayed_work(&scale3d.idle_timer, - msecs_to_jiffies((scale3d.p_idle_max * scale3d.p_fast_response) + msecs_to_jiffies((scale3d.idle_max * scale3d.fast_response) / 50000)); done: @@ -269,7 +392,6 @@ void nvhost_scale3d_notify_busy(struct nvhost_module *mod) t = ktime_get(); if (scale3d.is_idle) { - scale3d.last_busy = t; idle = (unsigned long) ktime_us_delta(t, scale3d.last_idle); scale3d.idle_total += idle; @@ -340,6 +462,7 @@ void nvhost_scale3d_debug_init(struct dentry *de) CREATE_SCALE3D_FILE(idle_min); CREATE_SCALE3D_FILE(idle_max); CREATE_SCALE3D_FILE(period); + CREATE_SCALE3D_FILE(adjust); CREATE_SCALE3D_FILE(verbosity); #undef CREATE_SCALE3D_FILE } @@ -388,11 +511,12 @@ void nvhost_scale3d_init(struct device *d, struct nvhost_module *mod) /* set scaling parameter defaults */ scale3d.enable = 0; - scale3d.p_period = 125000; - scale3d.p_idle_min = 10; - scale3d.p_idle_max = 15; - scale3d.p_fast_response = 6000; + scale3d.period = scale3d.p_period = 100000; + scale3d.idle_min = scale3d.p_idle_min = 10; + scale3d.idle_max = scale3d.p_idle_max = 15; + scale3d.fast_response = scale3d.p_fast_response = 7000; scale3d.p_verbosity = 0; + scale3d.p_adjust = 1; error = device_create_file(d, &dev_attr_enable_3d_scaling); if (error) |