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

Commit 7aef3b1f authored by Raju P.L.S.S.S.N's avatar Raju P.L.S.S.S.N Committed by Mahesh Sivasubramanian
Browse files

lpm-levels: Fix low power mode selection



The low power mode selection logic has problems while
selecting best mode both in cpu and cluster selection.
When latency requirement is not met, the level selection
loop breaks without selecting another possible shallow
power mode that meets both latency and residency
requirements. The residencies are initialized to ~0
(0xFFFFFFFF) when a particular mode is disabled in idle
context. This results in wrong selection of shallower
mode in suspend context instead of selecting best possible
deepest low power mode (assuming the mode is enabled in
suspend context but disabled in idle context). This can
have impact on power.

The change addresses this by selecting a possible
shallower power mode that can meet the latency criteria.
It also initializes the residencies to 0 when a mode is
not allowed in idle context. This results in selection
of deepest low power mode in suspend context and
saves power.

Change-Id: Iae8b6ad74ef0f28d9c542315745577b1a5924664
Signed-off-by: default avatarRaju P.L.S.S.S.N <rplsssn@codeaurora.org>
parent 0fb5a62a
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -80,6 +80,14 @@ static void set_optimum_cpu_residency(struct lpm_cpu *cpu, int cpu_id,
	for (i = 0; i < cpu->nlevels; i++) {
		struct power_params *pwr = &cpu->levels[i].pwr;

		mode_avail = probe_time ||
			lpm_cpu_mode_allow(cpu_id, i, true);

		if (!mode_avail) {
			residency[i] = 0;
			continue;
		}

		residency[i] = ~0;
		for (j = i + 1; j < cpu->nlevels; j++) {
			mode_avail = probe_time ||
@@ -102,12 +110,20 @@ static void set_optimum_cluster_residency(struct lpm_cluster *cluster,
	for (i = 0; i < cluster->nlevels; i++) {
		struct power_params *pwr = &cluster->levels[i].pwr;

		pwr->max_residency = ~0;
		for (j = 0; j < cluster->nlevels; j++) {
			if (i >= j)
		mode_avail = probe_time ||
			lpm_cluster_mode_allow(cluster, i,
					true);

		if (!mode_avail) {
			pwr->max_residency = 0;
			continue;
		}

		pwr->max_residency = ~0;
		for (j = i+1; j < cluster->nlevels; j++) {
			mode_avail = probe_time ||
					lpm_cluster_mode_allow(cluster, j,
							true);
			if (mode_avail &&
				(pwr->max_residency > pwr->residencies[j]) &&
				(pwr->residencies[j] != 0))
+15 −14
Original line number Diff line number Diff line
@@ -456,24 +456,25 @@ static int cpu_power_select(struct cpuidle_device *dev,

		if (next_event_us) {
			if (next_event_us < lvl_latency_us)
				continue;
				break;

			if (((next_event_us - lvl_latency_us) < sleep_us) ||
					(next_event_us < sleep_us))
				next_wakeup_us = next_event_us - lvl_latency_us;
		}

		if (next_wakeup_us <= residency[i]) {
		best_level = i;

		if (next_event_us && next_event_us < sleep_us &&
				(mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
			modified_time_us
				= next_event_us - lvl_latency_us;
		else
			modified_time_us = 0;

		if (next_wakeup_us <= residency[i])
			break;
	}
	}

	if (modified_time_us)
		msm_pm_set_timer(modified_time_us);
@@ -570,10 +571,10 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle)
			continue;

		if (from_idle && latency_us < pwr_params->latency_us)
			continue;
			break;

		if (sleep_us < pwr_params->time_overhead_us)
			continue;
			break;

		if (suspend_in_progress && from_idle && level->notify_rpm)
			continue;
@@ -581,11 +582,11 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle)
		if (level->notify_rpm && msm_rpm_waiting_for_ack())
			continue;

		if (sleep_us <= pwr_params->max_residency) {
		best_level = i;

		if (sleep_us <= pwr_params->max_residency)
			break;
	}
	}

	return best_level;
}