예제 #1
0
static int devfreq_watermark_target_freq(struct devfreq *df,
			unsigned long *freq)
{
	struct wmark_gov_info *wmarkinfo = df->data;
	struct devfreq_dev_status dev_stat;
	int err;

	err = df->profile->get_dev_status(df->dev.parent, &dev_stat);
	if (err < 0)
		return err;

	switch (wmarkinfo->event) {
	case HIGH_WATERMARK_EVENT:
		*freq = freqlist_up(wmarkinfo, dev_stat.current_frequency);

		/* always enable low watermark */
		df->profile->set_low_wmark(df->dev.parent,
					   wmarkinfo->p_low_wmark);

		/* disable high watermark if no change */
		if (*freq == wmarkinfo->last_request)
			df->profile->set_high_wmark(df->dev.parent, 1000);
		break;
	case LOW_WATERMARK_EVENT:
		*freq = freqlist_down(wmarkinfo, dev_stat.current_frequency);

		/* always enable high watermark */
		df->profile->set_high_wmark(df->dev.parent,
					    wmarkinfo->p_high_wmark);

		/* disable low watermark if no change */
		if (*freq == wmarkinfo->last_request)
			df->profile->set_low_wmark(df->dev.parent, 0);
		break;
	default:
		break;
	}

	/* Mark that you handled event */
	wmarkinfo->event = NO_WATERMARK_EVENT;
	wmarkinfo->last_request = *freq;

	return 0;
}
예제 #2
0
static void update_watermarks(struct devfreq *df,
			      unsigned long current_frequency,
			      unsigned long ideal_frequency)
{
	struct wmark_gov_info *wmarkinfo = df->data;
	unsigned long long relation = 0, next_freq = 0;
	unsigned long long current_frequency_khz = current_frequency / 1000;

	if (ideal_frequency == wmarkinfo->freqlist[0]) {
		/* disable the low watermark if we are at lowest clock */
		df->profile->set_low_wmark(df->dev.parent, 0);
	} else {
		/* calculate the low threshold; what is the load value
		 * at which we would go into lower frequency given the
		 * that we are running at the new frequency? */
		next_freq = freqlist_down(wmarkinfo, ideal_frequency);
		relation = ((next_freq / current_frequency_khz) *
			wmarkinfo->p_load_target) / 1000;
		df->profile->set_low_wmark(df->dev.parent, relation);
	}

	if (ideal_frequency ==
	    wmarkinfo->freqlist[wmarkinfo->freq_count - 1]) {
		/* disable the high watermark if we are at highest clock */
		df->profile->set_high_wmark(df->dev.parent, 1000);
	} else {
		/* calculate the high threshold; what is the load value
		 * at which we would go into highest frequency given the
		 * that we are running at the new frequency? */
		next_freq = freqlist_up(wmarkinfo, ideal_frequency);
		relation = ((next_freq / current_frequency_khz) *
			wmarkinfo->p_load_target) / 1000;
		relation = min((unsigned long long)wmarkinfo->p_load_max,
			       relation);
		df->profile->set_high_wmark(df->dev.parent, relation);
	}
}
예제 #3
0
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);
}
예제 #4
0
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;
}