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

Commit 30952dd4 authored by Srinivas Rao L's avatar Srinivas Rao L Committed by Gerrit - the friendly Code Review server
Browse files

cpuidle: lpm-levels: Hold lock during tick_broadcast_enter



When a core is doing system pm enter, as a part of
the GIC workaround, it would save the distributor registers.
There is a window where other core is doing tick_broadcast_enter
which will disable broadcast timer interrupt and enable back.
If the GIC save for broadcast timer interrupt falls in this window
it would be saved as disabled which leads to GIC restore would
keep interrupt disabled after exiting from low power mode.

To avoid this, hold a lock during tick_broadcast_enter and
system pm enter.

Change-Id: I924aa1a14f8fe4dc55a0e0d90e82e7c0ace6ec4e
Signed-off-by: default avatarSrinivas Rao L <lsrao@codeaurora.org>
parent 69156e98
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ struct lpm_debug {
};

static struct system_pm_ops *sys_pm_ops;

static DEFINE_SPINLOCK(bc_timer_lock);

struct lpm_cluster *lpm_root_node;

@@ -1029,6 +1029,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
	struct lpm_cluster_level *level = &cluster->levels[idx];
	struct cpumask online_cpus, cpumask;
	unsigned int cpu;
	int ret = 0;

	cpumask_and(&online_cpus, &cluster->num_children_in_sync,
					cpu_online_mask);
@@ -1067,10 +1068,14 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,

		clear_predict_history();
		clear_cl_predict_history();
		if (sys_pm_ops && sys_pm_ops->enter)
			if ((sys_pm_ops->enter(&cpumask)))
		if (sys_pm_ops && sys_pm_ops->enter) {
			spin_lock(&bc_timer_lock);
			ret = sys_pm_ops->enter(&cpumask);
			spin_unlock(&bc_timer_lock);
			if (ret)
				return -EBUSY;
		}
	}
	/* Notify cluster enter event after successfully config completion */
	cluster_notify(cluster, level, true);

@@ -1202,8 +1207,11 @@ static void cluster_unprepare(struct lpm_cluster *cluster,
	level = &cluster->levels[cluster->last_level];

	if (level->notify_rpm)
		if (sys_pm_ops && sys_pm_ops->exit)
		if (sys_pm_ops && sys_pm_ops->exit) {
			spin_lock(&bc_timer_lock);
			sys_pm_ops->exit();
			spin_unlock(&bc_timer_lock);
		}

	update_debug_pc_event(CLUSTER_EXIT, cluster->last_level,
			cluster->num_children_in_sync.bits[0],
@@ -1298,6 +1306,7 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle)
{
	int affinity_level = 0, state_id = 0, power_state = 0;
	bool success = false;
	int ret = 0;
	/*
	 * idx = 0 is the default LPM state
	 */
@@ -1310,7 +1319,17 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle)
	}

	if (from_idle && cpu->levels[idx].use_bc_timer) {
		if (tick_broadcast_enter())
		/*
		 * tick_broadcast_enter can change the affinity of the
		 * broadcast timer interrupt, during which interrupt will
		 * be disabled and enabled back. To avoid system pm ops
		 * doing any interrupt state save or restore in between
		 * this window hold the lock.
		 */
		spin_lock(&bc_timer_lock);
		ret = tick_broadcast_enter();
		spin_unlock(&bc_timer_lock);
		if (ret)
			return success;
	}