aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-07-07 10:29:38 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-07-07 12:46:47 -0400
commitf32dd117051185da6e923b35491a44d7debeeea5 (patch)
treeb714e69a520539388c31ee0fd2af28211a83aa82 /kernel
parente0454311903d3fd0f12a86c9e65d7b271c2bb05d (diff)
tick/broadcast: Make idle check independent from mode and config
Currently the broadcast busy check, which prevents the idle code from going into deep idle, works only in one shot mode. If NOHZ and HIGHRES are off (config or command line) there is no sanity check at all, so under certain conditions cpus are allowed to go into deep idle, where the local timer stops, and are not woken up again because there is no broadcast timer installed or a hrtimer based broadcast device is not evaluated. Move tick_broadcast_oneshot_control() into the common code and provide proper subfunctions for the various config combinations. The common check in tick_broadcast_oneshot_control() is for the C3STOP misfeature flag of the local clock event device. If its not set, idle can proceed. If set, further checks are necessary. Provide checks for the trivial cases: - If broadcast is disabled in the config, then return busy - If oneshot mode (NOHZ/HIGHES) is disabled in the config, return busy if the broadcast device is hrtimer based. - If oneshot mode is enabled in the config call the original tick_broadcast_oneshot_control() function. That function needs extra checks which will be implemented in seperate patches. [ Split out from a larger combo patch ] Reported-and-tested-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Suzuki Poulose <Suzuki.Poulose@arm.com> Cc: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com> Cc: Catalin Marinas <Catalin.Marinas@arm.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Preeti U Murthy <preeti@linux.vnet.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1507070929360.3916@nanos
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/tick-broadcast.c26
-rw-r--r--kernel/time/tick-common.c21
-rw-r--r--kernel/time/tick-sched.h10
3 files changed, 42 insertions, 15 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 9877d0b0aefc..ef77b16ad5df 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -685,18 +685,7 @@ static void broadcast_shutdown_local(struct clock_event_device *bc,
685 clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); 685 clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
686} 686}
687 687
688/** 688int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
689 * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
690 * @state: The target state (enter/exit)
691 *
692 * The system enters/leaves a state, where affected devices might stop
693 * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
694 *
695 * Called with interrupts disabled, so clockevents_lock is not
696 * required here because the local clock event device cannot go away
697 * under us.
698 */
699int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
700{ 689{
701 struct clock_event_device *bc, *dev; 690 struct clock_event_device *bc, *dev;
702 struct tick_device *td; 691 struct tick_device *td;
@@ -717,9 +706,6 @@ int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
717 td = this_cpu_ptr(&tick_cpu_device); 706 td = this_cpu_ptr(&tick_cpu_device);
718 dev = td->evtdev; 707 dev = td->evtdev;
719 708
720 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
721 return 0;
722
723 raw_spin_lock(&tick_broadcast_lock); 709 raw_spin_lock(&tick_broadcast_lock);
724 bc = tick_broadcast_device.evtdev; 710 bc = tick_broadcast_device.evtdev;
725 cpu = smp_processor_id(); 711 cpu = smp_processor_id();
@@ -961,6 +947,16 @@ bool tick_broadcast_oneshot_available(void)
961 return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false; 947 return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
962} 948}
963 949
950#else
951int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
952{
953 struct clock_event_device *bc = tick_broadcast_device.evtdev;
954
955 if (!bc || (bc->features & CLOCK_EVT_FEAT_HRTIMER))
956 return -EBUSY;
957
958 return 0;
959}
964#endif 960#endif
965 961
966void __init tick_broadcast_init(void) 962void __init tick_broadcast_init(void)
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 76446cb5dfe1..55e13efff1ab 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -343,6 +343,27 @@ out_bc:
343 tick_install_broadcast_device(newdev); 343 tick_install_broadcast_device(newdev);
344} 344}
345 345
346/**
347 * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
348 * @state: The target state (enter/exit)
349 *
350 * The system enters/leaves a state, where affected devices might stop
351 * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
352 *
353 * Called with interrupts disabled, so clockevents_lock is not
354 * required here because the local clock event device cannot go away
355 * under us.
356 */
357int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
358{
359 struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
360
361 if (!(td->evtdev->features & CLOCK_EVT_FEAT_C3STOP))
362 return 0;
363
364 return __tick_broadcast_oneshot_control(state);
365}
366
346#ifdef CONFIG_HOTPLUG_CPU 367#ifdef CONFIG_HOTPLUG_CPU
347/* 368/*
348 * Transfer the do_timer job away from a dying cpu. 369 * Transfer the do_timer job away from a dying cpu.
diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h
index 42fdf4958bcc..a4a8d4e9baa1 100644
--- a/kernel/time/tick-sched.h
+++ b/kernel/time/tick-sched.h
@@ -71,4 +71,14 @@ extern void tick_cancel_sched_timer(int cpu);
71static inline void tick_cancel_sched_timer(int cpu) { } 71static inline void tick_cancel_sched_timer(int cpu) { }
72#endif 72#endif
73 73
74#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
75extern int __tick_broadcast_oneshot_control(enum tick_broadcast_state state);
76#else
77static inline int
78__tick_broadcast_oneshot_control(enum tick_broadcast_state state)
79{
80 return -EBUSY;
81}
82#endif
83
74#endif 84#endif