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

Commit 706c74e0 authored by Olav Haugan's avatar Olav Haugan Committed by Satya Durga Srinivasu Prabhala
Browse files

hrtimer: Ensure timer is not running before migrating



A timer might be running when we are trying to move the timer to another
CPU so ensure that we wait for the timer to finish before migrating.

Change-Id: I1dfb57e4dd1bc676193e7ffe4b0d14a5e0df3d00
Signed-off-by: default avatarOlav Haugan <ohaugan@codeaurora.org>
[rameezmustafa@codeaurora.org: Port to msm-4.9]
Signed-off-by: default avatarSyed Rameez Mustafa <rameezmustafa@codeaurora.org>
[satyap@codeaurora.org: Port to 4.19 and fix merge conflicts]
Signed-off-by: default avatarSatya Durga Srinivasu Prabhala <satyap@codeaurora.org>
parent ec86ffd8
Loading
Loading
Loading
Loading
+29 −13
Original line number Diff line number Diff line
@@ -1832,20 +1832,35 @@ int hrtimers_prepare_cpu(unsigned int cpu)
}

#ifdef CONFIG_HOTPLUG_CPU
static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
				 struct hrtimer_clock_base *new_base,
static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
				 struct hrtimer_cpu_base *new_base,
				 unsigned int i, bool wait,
				 bool remove_pinned)
{
	struct hrtimer *timer;
	struct timerqueue_node *node;
	struct timerqueue_head pinned;
	int is_pinned;
	struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
	struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];

	timerqueue_init_head(&pinned);

	while ((node = timerqueue_getnext(&old_base->active))) {
	while ((node = timerqueue_getnext(&old_c_base->active))) {
		timer = container_of(node, struct hrtimer, node);
		if (wait) {
			/* Ensure timers are done running before continuing */
			while (hrtimer_callback_running(timer)) {
				raw_spin_unlock(&old_base->lock);
				raw_spin_unlock(&new_base->lock);
				cpu_relax();
				raw_spin_lock(&new_base->lock);
				raw_spin_lock_nested(&old_base->lock,
							SINGLE_DEPTH_NESTING);
			}
		} else {
			BUG_ON(hrtimer_callback_running(timer));
		}
		debug_deactivate(timer);

		/*
@@ -1853,7 +1868,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
		 * timer could be seen as !active and just vanish away
		 * under us on another CPU
		 */
		__remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
		__remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);

		is_pinned = timer->state & HRTIMER_STATE_PINNED;
		if (!remove_pinned && is_pinned) {
@@ -1861,7 +1876,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
			continue;
		}

		timer->base = new_base;
		timer->base = new_c_base;
		/*
		 * Enqueue the timers on the new cpu. This does not
		 * reprogram the event device in case the timer
@@ -1870,7 +1885,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
		 * sort out already expired timers and reprogram the
		 * event device.
		 */
		enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS);
		enqueue_hrtimer(timer, new_c_base, HRTIMER_MODE_ABS);
	}

	/* Re-queue pinned timers for non-hotplug usecase */
@@ -1878,11 +1893,12 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
		timer = container_of(node, struct hrtimer, node);

		timerqueue_del(&pinned, &timer->node);
		enqueue_hrtimer(timer, old_base, HRTIMER_MODE_ABS);
		enqueue_hrtimer(timer, old_c_base, HRTIMER_MODE_ABS);
	}
}

static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
static void
__migrate_hrtimers(unsigned int scpu, bool wait, bool remove_pinned)
{
	struct hrtimer_cpu_base *old_base, *new_base;
	unsigned long flags;
@@ -1905,8 +1921,8 @@ static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
	raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);

	for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
		migrate_hrtimer_list(&old_base->clock_base[i],
				     &new_base->clock_base[i], remove_pinned);
		migrate_hrtimer_list(old_base, new_base, i, wait,
								remove_pinned);
	}

	/*
@@ -1929,13 +1945,13 @@ int hrtimers_dead_cpu(unsigned int scpu)
	BUG_ON(cpu_online(scpu));
	tick_cancel_sched_timer(scpu);

	__migrate_hrtimers(scpu, true);
	__migrate_hrtimers(scpu, false, true);
	return 0;
}

void hrtimer_quiesce_cpu(void *cpup)
{
	__migrate_hrtimers(*(int *)cpup, false);
	__migrate_hrtimers(*(int *)cpup, true, false);
}

#endif /* CONFIG_HOTPLUG_CPU */