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

Commit 16323e6e authored by Murali Nalajala's avatar Murali Nalajala
Browse files

cpu_pm: Add level to the cluster pm notification



Cluster pm notifications without level information increases difficulty
and complexity for the registered drivers to figure out when the last
coherency level is going into power collapse.

Send notifications with level information that allows the registered
drivers to easily determine the cluster level that is going in/out of
power collapse.

There is an issue with this implementation. GIC driver saves and
restores the distributed registers as part of cluster notifications. On
newer platforms there are multiple cluster levels are defined (e.g l2,
cci etc). These cluster level notofications can happen independently.
On MSM platforms GIC is still active while the cluster sleeps in idle,
causing the GIC state to be overwritten with an incorrect previous state
of the interrupts. This leads to a system hang. Do not save and restore
on any L2 and higher cache coherency level sleep entry and exit.

Change-Id: I31918d6383f19e80fe3b064cfaf0b55e16b97eb6
Signed-off-by: default avatarArchana Sathyakumar <asathyak@codeaurora.org>
Signed-off-by: default avatarMurali Nalajala <mnalajal@codeaurora.org>
parent d9c0d608
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -42,12 +42,12 @@ static int highbank_suspend_finish(unsigned long val)
static int highbank_pm_enter(suspend_state_t state)
{
	cpu_pm_enter();
	cpu_cluster_pm_enter();
	cpu_cluster_pm_enter(0);

	highbank_set_cpu_jump(0, cpu_resume);
	cpu_suspend(0, highbank_suspend_finish);

	cpu_cluster_pm_exit();
	cpu_cluster_pm_exit(0);
	cpu_pm_exit();

	highbank_smc1(0x102, 0x1);
+2 −2
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
		 */
		if ((cx->mpu_state == PWRDM_POWER_RET) &&
			(cx->mpu_logic_state == PWRDM_POWER_OFF))
				cpu_cluster_pm_enter();
				cpu_cluster_pm_enter(0);
	}

	omap4_enter_lowpower(dev->cpu, cx->cpu_state);
@@ -149,7 +149,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
	 */
	if ((cx->mpu_state == PWRDM_POWER_RET) &&
		(cx->mpu_logic_state == PWRDM_POWER_OFF))
		cpu_cluster_pm_exit();
		cpu_cluster_pm_exit(0);

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);

+2 −2
Original line number Diff line number Diff line
@@ -143,13 +143,13 @@ void tegra_idle_lp2_last(void)
{
	tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);

	cpu_cluster_pm_enter();
	cpu_cluster_pm_enter(0);
	suspend_cpu_complex();

	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);

	restore_cpu_complex();
	cpu_cluster_pm_exit();
	cpu_cluster_pm_exit(0);
}

enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
+4 −1
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014, 2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -655,6 +655,7 @@ struct lpm_cluster *parse_cluster(struct device_node *node,
			list_add(&child->list, &c->child);
			cpumask_or(&c->child_cpus, &c->child_cpus,
					&child->child_cpus);
			c->aff_level = child->aff_level + 1;
			continue;
		}

@@ -670,6 +671,8 @@ struct lpm_cluster *parse_cluster(struct device_node *node,

			if (parse_cpu_levels(n, c))
				goto failed_parse_cluster;

			c->aff_level = 1;
		}
	}

+5 −7
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -473,9 +473,8 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
		/*
		 * Notify that the cluster is entering a low power mode
		 */
		if (level->mode[i] == MSM_SPM_MODE_POWER_COLLAPSE) {
			cpu_cluster_pm_enter();
		}
		if (level->mode[i] == MSM_SPM_MODE_POWER_COLLAPSE)
			cpu_cluster_pm_enter(cluster->aff_level);
	}
	if (level->notify_rpm) {
		struct cpumask nextcpu;
@@ -623,9 +622,8 @@ static void cluster_unprepare(struct lpm_cluster *cluster,
		BUG_ON(ret);

		if (cluster->levels[last_level].mode[i] ==
				MSM_SPM_MODE_POWER_COLLAPSE) {
			cpu_cluster_pm_exit();
		}
				MSM_SPM_MODE_POWER_COLLAPSE)
			cpu_cluster_pm_exit(cluster->aff_level);
	}
unlock_return:
	spin_unlock(&cluster->sync_lock);
Loading