aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-04-02 20:01:10 -0400
committerIngo Molnar <mingo@kernel.org>2015-04-03 02:44:31 -0400
commit592a438ff3fea61d303c5784c209b3f1fd3e16df (patch)
tree8ce6cf8c2095a516e9226305649332bae70490a4 /kernel
parent3ff70551a942b4c1d3c2e96e31a5c6e369a6d0be (diff)
clockevents: Provide explicit broadcast control functions
clockevents_notify() is a leftover from the early design of the clockevents facility. It's really not a notification mechanism, it's a multiplex call. We are way better off to have explicit calls instead of this monstrosity. Split out the broadcast control into a separate function and provide inline helpers. Switch clockevents_notify() over. This will go away once all callers are converted. This also gets rid of the nested locking of clockevents_lock and broadcast_lock. The broadcast control functions do not require clockevents_lock. Only the managing functions (setup/shutdown/suspend/resume of the broadcast device require clockevents_lock. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Len Brown <lenb@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Tony Lindgren <tony@atomide.com> Link: http://lkml.kernel.org/r/8086559.ttsuS0n1Xr@vostro.rjw.lan Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/clockevents.c6
-rw-r--r--kernel/time/tick-broadcast.c62
-rw-r--r--kernel/time/tick-internal.h2
3 files changed, 32 insertions, 38 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 7af614829da1..599ff8d3fda5 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -656,9 +656,13 @@ int clockevents_notify(unsigned long reason, void *arg)
656 656
657 switch (reason) { 657 switch (reason) {
658 case CLOCK_EVT_NOTIFY_BROADCAST_ON: 658 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
659 tick_broadcast_enable();
660 break;
659 case CLOCK_EVT_NOTIFY_BROADCAST_OFF: 661 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
662 tick_broadcast_disable();
663 break;
660 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: 664 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
661 tick_broadcast_on_off(reason, arg); 665 tick_broadcast_force();
662 break; 666 break;
663 667
664 case CLOCK_EVT_NOTIFY_BROADCAST_ENTER: 668 case CLOCK_EVT_NOTIFY_BROADCAST_ENTER:
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f5e0fd5652dc..1a0bee04ef8c 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -33,7 +33,7 @@ static cpumask_var_t tick_broadcast_mask;
33static cpumask_var_t tick_broadcast_on; 33static cpumask_var_t tick_broadcast_on;
34static cpumask_var_t tmpmask; 34static cpumask_var_t tmpmask;
35static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); 35static DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
36static int tick_broadcast_force; 36static int tick_broadcast_forced;
37 37
38#ifdef CONFIG_TICK_ONESHOT 38#ifdef CONFIG_TICK_ONESHOT
39static void tick_broadcast_clear_oneshot(int cpu); 39static void tick_broadcast_clear_oneshot(int cpu);
@@ -326,49 +326,54 @@ unlock:
326 raw_spin_unlock(&tick_broadcast_lock); 326 raw_spin_unlock(&tick_broadcast_lock);
327} 327}
328 328
329/* 329/**
330 * Powerstate information: The system enters/leaves a state, where 330 * tick_broadcast_control - Enable/disable or force broadcast mode
331 * affected devices might stop 331 * @mode: The selected broadcast mode
332 *
333 * Called when the system enters a state where affected tick devices
334 * might stop. Note: TICK_BROADCAST_FORCE cannot be undone.
335 *
336 * Called with interrupts disabled, so clockevents_lock is not
337 * required here because the local clock event device cannot go away
338 * under us.
332 */ 339 */
333static void tick_do_broadcast_on_off(unsigned long *reason) 340void tick_broadcast_control(enum tick_broadcast_mode mode)
334{ 341{
335 struct clock_event_device *bc, *dev; 342 struct clock_event_device *bc, *dev;
336 struct tick_device *td; 343 struct tick_device *td;
337 unsigned long flags;
338 int cpu, bc_stopped; 344 int cpu, bc_stopped;
339 345
340 raw_spin_lock_irqsave(&tick_broadcast_lock, flags); 346 td = this_cpu_ptr(&tick_cpu_device);
341
342 cpu = smp_processor_id();
343 td = &per_cpu(tick_cpu_device, cpu);
344 dev = td->evtdev; 347 dev = td->evtdev;
345 bc = tick_broadcast_device.evtdev;
346 348
347 /* 349 /*
348 * Is the device not affected by the powerstate ? 350 * Is the device not affected by the powerstate ?
349 */ 351 */
350 if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP)) 352 if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
351 goto out; 353 return;
352 354
353 if (!tick_device_is_functional(dev)) 355 if (!tick_device_is_functional(dev))
354 goto out; 356 return;
355 357
358 raw_spin_lock(&tick_broadcast_lock);
359 cpu = smp_processor_id();
360 bc = tick_broadcast_device.evtdev;
356 bc_stopped = cpumask_empty(tick_broadcast_mask); 361 bc_stopped = cpumask_empty(tick_broadcast_mask);
357 362
358 switch (*reason) { 363 switch (mode) {
359 case CLOCK_EVT_NOTIFY_BROADCAST_ON: 364 case TICK_BROADCAST_FORCE:
360 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: 365 tick_broadcast_forced = 1;
366 case TICK_BROADCAST_ON:
361 cpumask_set_cpu(cpu, tick_broadcast_on); 367 cpumask_set_cpu(cpu, tick_broadcast_on);
362 if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) { 368 if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
363 if (tick_broadcast_device.mode == 369 if (tick_broadcast_device.mode ==
364 TICKDEV_MODE_PERIODIC) 370 TICKDEV_MODE_PERIODIC)
365 clockevents_shutdown(dev); 371 clockevents_shutdown(dev);
366 } 372 }
367 if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
368 tick_broadcast_force = 1;
369 break; 373 break;
370 case CLOCK_EVT_NOTIFY_BROADCAST_OFF: 374
371 if (tick_broadcast_force) 375 case TICK_BROADCAST_OFF:
376 if (tick_broadcast_forced)
372 break; 377 break;
373 cpumask_clear_cpu(cpu, tick_broadcast_on); 378 cpumask_clear_cpu(cpu, tick_broadcast_on);
374 if (!tick_device_is_functional(dev)) 379 if (!tick_device_is_functional(dev))
@@ -390,22 +395,9 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
390 else 395 else
391 tick_broadcast_setup_oneshot(bc); 396 tick_broadcast_setup_oneshot(bc);
392 } 397 }
393out: 398 raw_spin_unlock(&tick_broadcast_lock);
394 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
395}
396
397/*
398 * Powerstate information: The system enters/leaves a state, where
399 * affected devices might stop.
400 */
401void tick_broadcast_on_off(unsigned long reason, int *oncpu)
402{
403 if (!cpumask_test_cpu(*oncpu, cpu_online_mask))
404 printk(KERN_ERR "tick-broadcast: ignoring broadcast for "
405 "offline CPU #%d\n", *oncpu);
406 else
407 tick_do_broadcast_on_off(&reason);
408} 399}
400EXPORT_SYMBOL_GPL(tick_broadcast_control);
409 401
410/* 402/*
411 * Set the periodic handler depending on broadcast on/off 403 * Set the periodic handler depending on broadcast on/off
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index b6ba0a44e740..62e331d1bc76 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -53,7 +53,6 @@ extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt);
53extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu); 53extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu);
54extern void tick_install_broadcast_device(struct clock_event_device *dev); 54extern void tick_install_broadcast_device(struct clock_event_device *dev);
55extern int tick_is_broadcast_device(struct clock_event_device *dev); 55extern int tick_is_broadcast_device(struct clock_event_device *dev);
56extern void tick_broadcast_on_off(unsigned long reason, int *oncpu);
57extern void tick_shutdown_broadcast(unsigned int *cpup); 56extern void tick_shutdown_broadcast(unsigned int *cpup);
58extern void tick_suspend_broadcast(void); 57extern void tick_suspend_broadcast(void);
59extern void tick_resume_broadcast(void); 58extern void tick_resume_broadcast(void);
@@ -68,7 +67,6 @@ static inline void tick_install_broadcast_device(struct clock_event_device *dev)
68static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; } 67static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; }
69static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; } 68static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; }
70static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } 69static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
71static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { }
72static inline void tick_shutdown_broadcast(unsigned int *cpup) { } 70static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
73static inline void tick_suspend_broadcast(void) { } 71static inline void tick_suspend_broadcast(void) { }
74static inline void tick_resume_broadcast(void) { } 72static inline void tick_resume_broadcast(void) { }