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

Commit bbe849de authored by Lianwei Wang's avatar Lianwei Wang Committed by Amit Pundir
Browse files

cpufreq: interactive: resched timer if max freq raised



When the policy max freq is raised, and before the timer is
rescheduled in idle callback, the cpu freq may stuck at a
lower freq.

The target_freq shall be updated too, else on a high load
situation, the new_freq is always equal to target_freq and
which will cause freq stuck at a lower freq too.

Reschedule the timer on gov limits callback.

Change-Id: I6c187001ab43e859731429b64f75a74eebc37a24
Signed-off-by: default avatarLianwei Wang <a22439@motorola.com>
parent fc8229cf
Loading
Loading
Loading
Loading
+54 −10
Original line number Diff line number Diff line
@@ -189,6 +189,32 @@ static void cpufreq_interactive_timer_resched(
	spin_unlock_irqrestore(&pcpu->load_lock, flags);
}

/* The caller shall take enable_sem write semaphore to avoid any timer race.
 * The cpu_timer and cpu_slack_timer must be deactivated when calling this
 * function.
 */
static void cpufreq_interactive_timer_start(int cpu)
{
	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
	unsigned long expires = jiffies + usecs_to_jiffies(timer_rate);
	unsigned long flags;

	pcpu->cpu_timer.expires = expires;
	add_timer_on(&pcpu->cpu_timer, cpu);
	if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) {
		expires += usecs_to_jiffies(timer_slack_val);
		pcpu->cpu_slack_timer.expires = expires;
		add_timer_on(&pcpu->cpu_slack_timer, cpu);
	}

	spin_lock_irqsave(&pcpu->load_lock, flags);
	pcpu->time_in_idle =
		get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp);
	pcpu->cputime_speedadj = 0;
	pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
	spin_unlock_irqrestore(&pcpu->load_lock, flags);
}

static unsigned int freq_to_above_hispeed_delay(unsigned int freq)
{
	int i;
@@ -1058,8 +1084,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
			hispeed_freq = policy->max;

		for_each_cpu(j, policy->cpus) {
			unsigned long expires;

			pcpu = &per_cpu(cpuinfo, j);
			pcpu->policy = policy;
			pcpu->target_freq = policy->cur;
@@ -1070,14 +1094,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
			pcpu->hispeed_validate_time =
				pcpu->floor_validate_time;
			down_write(&pcpu->enable_sem);
			expires = jiffies + usecs_to_jiffies(timer_rate);
			pcpu->cpu_timer.expires = expires;
			add_timer_on(&pcpu->cpu_timer, j);
			if (timer_slack_val >= 0) {
				expires += usecs_to_jiffies(timer_slack_val);
				pcpu->cpu_slack_timer.expires = expires;
				add_timer_on(&pcpu->cpu_slack_timer, j);
			}
			cpufreq_interactive_timer_start(j);
			pcpu->governor_enabled = 1;
			up_write(&pcpu->enable_sem);
		}
@@ -1136,6 +1153,33 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
		else if (policy->min > policy->cur)
			__cpufreq_driver_target(policy,
					policy->min, CPUFREQ_RELATION_L);
		for_each_cpu(j, policy->cpus) {
			pcpu = &per_cpu(cpuinfo, j);

			/* hold write semaphore to avoid race */
			down_write(&pcpu->enable_sem);
			if (pcpu->governor_enabled == 0) {
				up_write(&pcpu->enable_sem);
				continue;
			}

			/* update target_freq firstly */
			if (policy->max < pcpu->target_freq)
				pcpu->target_freq = policy->max;
			else if (policy->min > pcpu->target_freq)
				pcpu->target_freq = policy->min;

			/* Reschedule timer.
			 * Delete the timers, else the timer callback may
			 * return without re-arm the timer when failed
			 * acquire the semaphore. This race may cause timer
			 * stopped unexpectedly.
			 */
			del_timer_sync(&pcpu->cpu_timer);
			del_timer_sync(&pcpu->cpu_slack_timer);
			cpufreq_interactive_timer_start(j);
			up_write(&pcpu->enable_sem);
		}
		break;
	}
	return 0;