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

Commit 86a84d6b authored by Prasad Sodagudi's avatar Prasad Sodagudi
Browse files

sched: Add a check for cpu unbound deferrable timers



Add a check for cpu unbound deferrable timer expiry and raise
softirq for handling the expired timers so that the CPU can
process the cpu unbound deferrable times as early as possible
when a cpu tries to enter/exit idle loop.

Change-Id: Ieffa74fa22a4d25493f5590b5ac1e0d784fcbbad
Signed-off-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
parent d4bc64ea
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -190,6 +190,9 @@ extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);

extern void set_timer_slack(struct timer_list *time, int slack_hz);
#ifdef CONFIG_SMP
extern bool check_pending_deferrable_timers(int cpu);
#endif

#define TIMER_NOT_PINNED	0
#define TIMER_PINNED		1
+6 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/percpu.h>
#include <linux/profile.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/module.h>
#include <linux/irq_work.h>
#include <linux/posix-timers.h>
@@ -829,6 +830,11 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts)

	now = tick_nohz_start_idle(ts);

#ifdef CONFIG_SMP
	if (check_pending_deferrable_timers(cpu))
		raise_softirq_irqoff(TIMER_SOFTIRQ);
#endif

	if (can_stop_idle_tick(cpu, ts)) {
		int was_stopped = ts->tick_stopped;

+32 −3
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ EXPORT_SYMBOL(boot_tvec_bases);
static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;
#ifdef CONFIG_SMP
struct tvec_base tvec_base_deferrable;
static atomic_t deferrable_pending;
#endif

static inline void __run_timers(struct tvec_base *base);
@@ -676,9 +677,13 @@ static inline bool is_deferrable_timer_base(struct tvec_base *base)

static inline void __run_deferrable_timers(void)
{
	if (smp_processor_id() == tick_do_timer_cpu &&
	    time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies))
	if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) {
		if ((atomic_cmpxchg(&deferrable_pending, 1, 0) &&
			tick_do_timer_cpu == TICK_DO_TIMER_NONE) ||
			tick_do_timer_cpu == smp_processor_id())
				__run_timers(&tvec_base_deferrable);

	}
}

static inline void init_deferrable_timer(void)
@@ -1402,6 +1407,30 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
	return expires;
}

#ifdef CONFIG_SMP
/*
 * check_pending_deferrable_timers - Check for unbound deferrable timer expiry.
 * @cpu - Current CPU
 *
 * The function checks whether any global deferrable pending timers
 * are exipired or not. This function does not check cpu bounded
 * diferrable pending timers expiry.
 *
 * The function returns true when a cpu unbounded deferrable timer is expired.
 */
bool check_pending_deferrable_timers(int cpu)
{
	if (cpu == tick_do_timer_cpu ||
		tick_do_timer_cpu == TICK_DO_TIMER_NONE) {
		if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)
			&& !atomic_cmpxchg(&deferrable_pending, 0, 1)) {
				return true;
		}
	}
	return false;
}
#endif

/**
 * get_next_timer_interrupt - return the jiffy of the next pending timer
 * @now: current time (in jiffies)