aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-broadcast.c
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2013-02-08 10:24:07 -0500
committerThomas Gleixner <tglx@linutronix.de>2013-02-12 14:22:28 -0500
commit5d1d9a29bc0772abee765f09513779a2ef0ebbfd (patch)
tree7905268873812518cf4f6196f2100e5224733f22 /kernel/time/tick-broadcast.c
parent12ad10004645d38356b14d1fbba379c523a61916 (diff)
clockevents: Fix generic broadcast for FEAT_C3STOP
Commit 12ad100046: "clockevents: Add generic timer broadcast function" made tick_device_uses_broadcast set up the generic broadcast function for dummy devices (where !tick_device_is_functional(dev)), but neglected to set up the broadcast function for devices that stop in low power states (with the CLOCK_EVT_FEAT_C3STOP flag). When these devices enter low power states they will not have the generic broadcast function assigned, and will bring down the system when an attempt is made to broadcast to them. This patch ensures that the broadcast function is also assigned for devices which require broadcast in low power states. Reported-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Tested-by: Stephen Warren <swarren@nvidia.com> Cc: linux-arm-kernel@lists.infradead.org Cc: nico@linaro.org Cc: Marc.Zyngier@arm.com Cc: Will.Deacon@arm.com Cc: santosh.shilimkar@ti.com Cc: john.stultz@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/tick-broadcast.c')
-rw-r--r--kernel/time/tick-broadcast.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f726537d24eb..2fb8cb88df8d 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -92,6 +92,17 @@ static void err_broadcast(const struct cpumask *mask)
92 pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n"); 92 pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
93} 93}
94 94
95static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
96{
97 if (!dev->broadcast)
98 dev->broadcast = tick_broadcast;
99 if (!dev->broadcast) {
100 pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
101 dev->name);
102 dev->broadcast = err_broadcast;
103 }
104}
105
95/* 106/*
96 * Check, if the device is disfunctional and a place holder, which 107 * Check, if the device is disfunctional and a place holder, which
97 * needs to be handled by the broadcast device. 108 * needs to be handled by the broadcast device.
@@ -111,13 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
111 */ 122 */
112 if (!tick_device_is_functional(dev)) { 123 if (!tick_device_is_functional(dev)) {
113 dev->event_handler = tick_handle_periodic; 124 dev->event_handler = tick_handle_periodic;
114 if (!dev->broadcast) 125 tick_device_setup_broadcast_func(dev);
115 dev->broadcast = tick_broadcast;
116 if (!dev->broadcast) {
117 pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
118 dev->name);
119 dev->broadcast = err_broadcast;
120 }
121 cpumask_set_cpu(cpu, tick_get_broadcast_mask()); 126 cpumask_set_cpu(cpu, tick_get_broadcast_mask());
122 tick_broadcast_start_periodic(tick_broadcast_device.evtdev); 127 tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
123 ret = 1; 128 ret = 1;
@@ -129,9 +134,10 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
129 */ 134 */
130 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { 135 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
131 int cpu = smp_processor_id(); 136 int cpu = smp_processor_id();
132
133 cpumask_clear_cpu(cpu, tick_get_broadcast_mask()); 137 cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
134 tick_broadcast_clear_oneshot(cpu); 138 tick_broadcast_clear_oneshot(cpu);
139 } else {
140 tick_device_setup_broadcast_func(dev);
135 } 141 }
136 } 142 }
137 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); 143 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);