Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 374d2573 authored by Junjie Wu's avatar Junjie Wu Committed by Matt Wagantall
Browse files

cpufreq: interactive: Reschedule timer if min_freq is reduced



When a CPU is running at policy->min, slack timer will not be scheduled.
If policy->min is reduced later, current implementation doesn't
reschedule slack timer and thus could leave CPU at a higher
frequency indefinitely as long as the CPU is idle. This behavior is
undesirable from power perspective.

Change-Id: I40bfd7c93ad3fd06e3837dc48befdc07f29c78c8
Signed-off-by: default avatarJunjie Wu <junjiew@codeaurora.org>
parent 38f184a9
Loading
Loading
Loading
Loading
+22 −12
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ struct cpufreq_interactive_cpuinfo {
	unsigned int target_freq;
	unsigned int floor_freq;
	unsigned int max_freq;
	unsigned int min_freq;
	u64 floor_validate_time;
	u64 local_fvtime; /* per-cpu floor_validate_time */
	u64 hispeed_validate_time; /* cluster hispeed_validate_time */
@@ -172,7 +173,8 @@ static inline int set_window_helper(
			 usecs_to_jiffies(tunables->timer_rate));
}

static void cpufreq_interactive_timer_resched(unsigned long cpu)
static void cpufreq_interactive_timer_resched(unsigned long cpu,
					      bool slack_only)
{
	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
	struct cpufreq_interactive_tunables *tunables =
@@ -181,16 +183,18 @@ static void cpufreq_interactive_timer_resched(unsigned long cpu)
	unsigned long flags;

	spin_lock_irqsave(&pcpu->load_lock, flags);
	expires = round_to_nw_start(pcpu->last_evaluated_jiffy, tunables);
	if (!slack_only) {
		pcpu->time_in_idle =
			get_cpu_idle_time(smp_processor_id(),
				  &pcpu->time_in_idle_timestamp,
				  tunables->io_is_busy);
		pcpu->cputime_speedadj = 0;
		pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
	expires = round_to_nw_start(pcpu->last_evaluated_jiffy, tunables);
		del_timer(&pcpu->cpu_timer);
		pcpu->cpu_timer.expires = expires;
		add_timer_on(&pcpu->cpu_timer, cpu);
	}

	if (tunables->timer_slack_val >= 0 &&
	    pcpu->target_freq > pcpu->policy->min) {
@@ -557,7 +561,7 @@ static void cpufreq_interactive_timer(unsigned long data)

rearm:
	if (!timer_pending(&pcpu->cpu_timer))
		cpufreq_interactive_timer_resched(data);
		cpufreq_interactive_timer_resched(data, false);

exit:
	up_read(&pcpu->enable_sem);
@@ -579,7 +583,7 @@ static void cpufreq_interactive_idle_end(void)

	/* Arm the timer for 1-2 ticks later if not already. */
	if (!timer_pending(&pcpu->cpu_timer)) {
		cpufreq_interactive_timer_resched(smp_processor_id());
		cpufreq_interactive_timer_resched(smp_processor_id(), false);
	} else if (time_after_eq(jiffies, pcpu->cpu_timer.expires)) {
		del_timer(&pcpu->cpu_timer);
		del_timer(&pcpu->cpu_slack_timer);
@@ -1613,6 +1617,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
				pcpu->floor_validate_time;
			pcpu->local_hvtime = pcpu->floor_validate_time;
			pcpu->max_freq = policy->max;
			pcpu->min_freq = policy->min;
			pcpu->reject_notification = true;
			down_write(&pcpu->enable_sem);
			del_timer_sync(&pcpu->cpu_timer);
@@ -1666,6 +1671,11 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
				pcpu->target_freq = policy->min;

			spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);

			if (policy->min < pcpu->min_freq)
				cpufreq_interactive_timer_resched(j, true);
			pcpu->min_freq = policy->min;

			up_read(&pcpu->enable_sem);

			/* Reschedule timer only if policy->max is raised.
@@ -1680,7 +1690,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
				down_write(&pcpu->enable_sem);
				del_timer_sync(&pcpu->cpu_timer);
				del_timer_sync(&pcpu->cpu_slack_timer);
				cpufreq_interactive_timer_resched(j);
				cpufreq_interactive_timer_resched(j, false);
				up_write(&pcpu->enable_sem);
				pcpu->reject_notification = false;
			}