aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/tick-common.c')
-rw-r--r--kernel/time/tick-common.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 46e4381c26ea..48167a6ae55c 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -20,17 +20,19 @@
20#include <linux/sched.h> 20#include <linux/sched.h>
21#include <linux/tick.h> 21#include <linux/tick.h>
22 22
23#include "tick-internal.h"
24
23/* 25/*
24 * Tick devices 26 * Tick devices
25 */ 27 */
26static DEFINE_PER_CPU(struct tick_device, tick_cpu_device); 28DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
27/* 29/*
28 * Tick next event: keeps track of the tick time 30 * Tick next event: keeps track of the tick time
29 */ 31 */
30static ktime_t tick_next_period; 32ktime_t tick_next_period;
31static ktime_t tick_period; 33ktime_t tick_period;
32static int tick_do_timer_cpu = -1; 34static int tick_do_timer_cpu = -1;
33static DEFINE_SPINLOCK(tick_device_lock); 35DEFINE_SPINLOCK(tick_device_lock);
34 36
35/* 37/*
36 * Periodic tick 38 * Periodic tick
@@ -78,9 +80,13 @@ void tick_handle_periodic(struct clock_event_device *dev)
78/* 80/*
79 * Setup the device for a periodic tick 81 * Setup the device for a periodic tick
80 */ 82 */
81void tick_setup_periodic(struct clock_event_device *dev) 83void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
82{ 84{
83 dev->event_handler = tick_handle_periodic; 85 tick_set_periodic_handler(dev, broadcast);
86
87 /* Broadcast setup ? */
88 if (!tick_device_is_functional(dev))
89 return;
84 90
85 if (dev->features & CLOCK_EVT_FEAT_PERIODIC) { 91 if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
86 clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); 92 clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
@@ -145,6 +151,15 @@ static void tick_setup_device(struct tick_device *td,
145 if (!cpus_equal(newdev->cpumask, cpumask)) 151 if (!cpus_equal(newdev->cpumask, cpumask))
146 irq_set_affinity(newdev->irq, cpumask); 152 irq_set_affinity(newdev->irq, cpumask);
147 153
154 /*
155 * When global broadcasting is active, check if the current
156 * device is registered as a placeholder for broadcast mode.
157 * This allows us to handle this x86 misfeature in a generic
158 * way.
159 */
160 if (tick_device_uses_broadcast(newdev, cpu))
161 return;
162
148 if (td->mode == TICKDEV_MODE_PERIODIC) 163 if (td->mode == TICKDEV_MODE_PERIODIC)
149 tick_setup_periodic(newdev, 0); 164 tick_setup_periodic(newdev, 0);
150} 165}
@@ -197,19 +212,33 @@ static int tick_check_new_device(struct clock_event_device *newdev)
197 * Check the rating 212 * Check the rating
198 */ 213 */
199 if (curdev->rating >= newdev->rating) 214 if (curdev->rating >= newdev->rating)
200 goto out; 215 goto out_bc;
201 } 216 }
202 217
203 /* 218 /*
204 * Replace the eventually existing device by the new 219 * Replace the eventually existing device by the new
205 * device. 220 * device. If the current device is the broadcast device, do
221 * not give it back to the clockevents layer !
206 */ 222 */
223 if (tick_is_broadcast_device(curdev)) {
224 clockevents_set_mode(curdev, CLOCK_EVT_MODE_SHUTDOWN);
225 curdev = NULL;
226 }
207 clockevents_exchange_device(curdev, newdev); 227 clockevents_exchange_device(curdev, newdev);
208 tick_setup_device(td, newdev, cpu, cpumask); 228 tick_setup_device(td, newdev, cpu, cpumask);
209 ret = NOTIFY_STOP;
210 229
230 spin_unlock_irqrestore(&tick_device_lock, flags);
231 return NOTIFY_STOP;
232
233out_bc:
234 /*
235 * Can the new device be used as a broadcast device ?
236 */
237 if (tick_check_broadcast_device(newdev))
238 ret = NOTIFY_STOP;
211out: 239out:
212 spin_unlock_irqrestore(&tick_device_lock, flags); 240 spin_unlock_irqrestore(&tick_device_lock, flags);
241
213 return ret; 242 return ret;
214} 243}
215 244
@@ -251,7 +280,13 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
251 case CLOCK_EVT_NOTIFY_ADD: 280 case CLOCK_EVT_NOTIFY_ADD:
252 return tick_check_new_device(dev); 281 return tick_check_new_device(dev);
253 282
283 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
284 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
285 tick_broadcast_on_off(reason, dev);
286 break;
287
254 case CLOCK_EVT_NOTIFY_CPU_DEAD: 288 case CLOCK_EVT_NOTIFY_CPU_DEAD:
289 tick_shutdown_broadcast(dev);
255 tick_shutdown(dev); 290 tick_shutdown(dev);
256 break; 291 break;
257 292