aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-broadcast.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/tick-broadcast.c')
-rw-r--r--kernel/time/tick-broadcast.c70
1 files changed, 59 insertions, 11 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 20d6fba70652..c389f068aca2 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -29,6 +29,7 @@
29 29
30static struct tick_device tick_broadcast_device; 30static struct tick_device tick_broadcast_device;
31static cpumask_var_t tick_broadcast_mask; 31static cpumask_var_t tick_broadcast_mask;
32static cpumask_var_t tick_broadcast_on;
32static cpumask_var_t tmpmask; 33static cpumask_var_t tmpmask;
33static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); 34static DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
34static int tick_broadcast_force; 35static int tick_broadcast_force;
@@ -123,8 +124,9 @@ static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
123 */ 124 */
124int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) 125int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
125{ 126{
127 struct clock_event_device *bc = tick_broadcast_device.evtdev;
126 unsigned long flags; 128 unsigned long flags;
127 int ret = 0; 129 int ret;
128 130
129 raw_spin_lock_irqsave(&tick_broadcast_lock, flags); 131 raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
130 132
@@ -138,20 +140,59 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
138 dev->event_handler = tick_handle_periodic; 140 dev->event_handler = tick_handle_periodic;
139 tick_device_setup_broadcast_func(dev); 141 tick_device_setup_broadcast_func(dev);
140 cpumask_set_cpu(cpu, tick_broadcast_mask); 142 cpumask_set_cpu(cpu, tick_broadcast_mask);
141 tick_broadcast_start_periodic(tick_broadcast_device.evtdev); 143 tick_broadcast_start_periodic(bc);
142 ret = 1; 144 ret = 1;
143 } else { 145 } else {
144 /* 146 /*
145 * When the new device is not affected by the stop 147 * Clear the broadcast bit for this cpu if the
146 * feature and the cpu is marked in the broadcast mask 148 * device is not power state affected.
147 * then clear the broadcast bit.
148 */ 149 */
149 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { 150 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
150 int cpu = smp_processor_id();
151 cpumask_clear_cpu(cpu, tick_broadcast_mask); 151 cpumask_clear_cpu(cpu, tick_broadcast_mask);
152 tick_broadcast_clear_oneshot(cpu); 152 else
153 } else {
154 tick_device_setup_broadcast_func(dev); 153 tick_device_setup_broadcast_func(dev);
154
155 /*
156 * Clear the broadcast bit if the CPU is not in
157 * periodic broadcast on state.
158 */
159 if (!cpumask_test_cpu(cpu, tick_broadcast_on))
160 cpumask_clear_cpu(cpu, tick_broadcast_mask);
161
162 switch (tick_broadcast_device.mode) {
163 case TICKDEV_MODE_ONESHOT:
164 /*
165 * If the system is in oneshot mode we can
166 * unconditionally clear the oneshot mask bit,
167 * because the CPU is running and therefore
168 * not in an idle state which causes the power
169 * state affected device to stop. Let the
170 * caller initialize the device.
171 */
172 tick_broadcast_clear_oneshot(cpu);
173 ret = 0;
174 break;
175
176 case TICKDEV_MODE_PERIODIC:
177 /*
178 * If the system is in periodic mode, check
179 * whether the broadcast device can be
180 * switched off now.
181 */
182 if (cpumask_empty(tick_broadcast_mask) && bc)
183 clockevents_shutdown(bc);
184 /*
185 * If we kept the cpu in the broadcast mask,
186 * tell the caller to leave the per cpu device
187 * in shutdown state. The periodic interrupt
188 * is delivered by the broadcast device.
189 */
190 ret = cpumask_test_cpu(cpu, tick_broadcast_mask);
191 break;
192 default:
193 /* Nothing to do */
194 ret = 0;
195 break;
155 } 196 }
156 } 197 }
157 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); 198 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -281,6 +322,7 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
281 switch (*reason) { 322 switch (*reason) {
282 case CLOCK_EVT_NOTIFY_BROADCAST_ON: 323 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
283 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: 324 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
325 cpumask_set_cpu(cpu, tick_broadcast_on);
284 if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) { 326 if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
285 if (tick_broadcast_device.mode == 327 if (tick_broadcast_device.mode ==
286 TICKDEV_MODE_PERIODIC) 328 TICKDEV_MODE_PERIODIC)
@@ -290,8 +332,12 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
290 tick_broadcast_force = 1; 332 tick_broadcast_force = 1;
291 break; 333 break;
292 case CLOCK_EVT_NOTIFY_BROADCAST_OFF: 334 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
293 if (!tick_broadcast_force && 335 if (tick_broadcast_force)
294 cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) { 336 break;
337 cpumask_clear_cpu(cpu, tick_broadcast_on);
338 if (!tick_device_is_functional(dev))
339 break;
340 if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) {
295 if (tick_broadcast_device.mode == 341 if (tick_broadcast_device.mode ==
296 TICKDEV_MODE_PERIODIC) 342 TICKDEV_MODE_PERIODIC)
297 tick_setup_periodic(dev, 0); 343 tick_setup_periodic(dev, 0);
@@ -349,6 +395,7 @@ void tick_shutdown_broadcast(unsigned int *cpup)
349 395
350 bc = tick_broadcast_device.evtdev; 396 bc = tick_broadcast_device.evtdev;
351 cpumask_clear_cpu(cpu, tick_broadcast_mask); 397 cpumask_clear_cpu(cpu, tick_broadcast_mask);
398 cpumask_clear_cpu(cpu, tick_broadcast_on);
352 399
353 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { 400 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
354 if (bc && cpumask_empty(tick_broadcast_mask)) 401 if (bc && cpumask_empty(tick_broadcast_mask))
@@ -792,6 +839,7 @@ bool tick_broadcast_oneshot_available(void)
792void __init tick_broadcast_init(void) 839void __init tick_broadcast_init(void)
793{ 840{
794 zalloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT); 841 zalloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT);
842 zalloc_cpumask_var(&tick_broadcast_on, GFP_NOWAIT);
795 zalloc_cpumask_var(&tmpmask, GFP_NOWAIT); 843 zalloc_cpumask_var(&tmpmask, GFP_NOWAIT);
796#ifdef CONFIG_TICK_ONESHOT 844#ifdef CONFIG_TICK_ONESHOT
797 zalloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT); 845 zalloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT);