void nvhost_scale3d_set_throughput_hint(int hint) { struct podgov_info_rec *podgov = local_podgov; struct devfreq *df; long idle; long curr, target; int avg_idle, avg_hint, scale_score; unsigned int smooth; if (!podgov) return; df = podgov->power_manager; if (!df) return; mutex_lock(&podgov->power_manager->lock); podgov->block--; if (!podgov->enable || !podgov->p_use_throughput_hint || podgov->block > 0) { mutex_unlock(&podgov->power_manager->lock); return; } trace_podgov_hint(podgov->idle_estimate, hint); podgov->last_throughput_hint = ktime_get(); curr = podgov->power_manager->previous_freq; idle = podgov->idle_estimate; smooth = podgov->p_smooth; /* compute averages usings exponential-moving-average */ avg_idle = ((smooth*podgov->idle_avg + idle)/(smooth+1)); podgov->idle_avg = avg_idle; avg_hint = ((smooth*podgov->hint_avg + hint)/(smooth+1)); podgov->hint_avg = avg_hint; /* set the target using avg_hint and avg_idle */ if (avg_hint < podgov->p_hint_lo_limit) { target = freqlist_up(podgov, curr, 1); } else if (avg_hint > podgov->p_hint_hi_limit) { target = freqlist_down(podgov, curr, 1); } else { scale_score = avg_idle + avg_hint; if (scale_score > podgov->p_scaledown_limit) target = freqlist_down(podgov, curr, 1); else if (scale_score < podgov->p_scaleup_limit) target = freqlist_up(podgov, curr, 1); else target = curr; } /* clamp and apply target */ scaling_limit(df, &target); if (target != curr) { podgov->block = podgov->p_smooth; trace_podgov_do_scale(df->previous_freq, target); podgov->adjustment_frequency = target; podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } trace_podgov_print_target(idle, avg_idle, curr / 1000000, target, hint, avg_hint); mutex_unlock(&podgov->power_manager->lock); }
static int nvhost_scale3d_set_throughput_hint(struct notifier_block *nb, unsigned long action, void *data) { struct podgov_info_rec *podgov = container_of(nb, struct podgov_info_rec, throughput_hint_notifier); struct devfreq *df; struct platform_device *pdev; int hint = tegra_throughput_get_hint(); long idle; long curr, target; int avg_idle, avg_hint, scale_score; unsigned int smooth; if (!podgov) return NOTIFY_DONE; df = podgov->power_manager; if (!df) return NOTIFY_DONE; pdev = to_platform_device(df->dev.parent); /* make sure the device is alive before doing any scaling */ nvhost_module_busy_noresume(pdev); if (!pm_runtime_active(&pdev->dev)) { nvhost_module_idle(pdev); return 0; } mutex_lock(&podgov->power_manager->lock); podgov->block--; if (!podgov->enable || !podgov->p_use_throughput_hint || podgov->block > 0) goto exit_unlock; trace_podgov_hint(podgov->idle, hint); podgov->last_throughput_hint = ktime_get(); curr = podgov->power_manager->previous_freq; idle = podgov->idle; avg_idle = podgov->idle_avg; smooth = podgov->p_smooth; /* compute averages usings exponential-moving-average */ avg_hint = ((smooth*podgov->hint_avg + hint)/(smooth+1)); podgov->hint_avg = avg_hint; /* set the target using avg_hint and avg_idle */ target = curr; if (avg_hint < podgov->p_hint_lo_limit) { target = freqlist_up(podgov, curr, 1); } else { scale_score = avg_idle + avg_hint; if (scale_score > podgov->p_scaledown_limit) target = freqlist_down(podgov, curr, 1); else if (scale_score < podgov->p_scaleup_limit && hint < podgov->p_hint_hi_limit) target = freqlist_up(podgov, curr, 1); } /* clamp and apply target */ scaling_limit(df, &target); if (target != curr) { podgov->block = podgov->p_smooth; trace_podgov_do_scale(df->previous_freq, target); podgov->adjustment_frequency = target; podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } trace_podgov_print_target(idle, avg_idle, curr / 1000000, target, hint, avg_hint); exit_unlock: mutex_unlock(&podgov->power_manager->lock); nvhost_module_idle(pdev); return NOTIFY_OK; }