aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/time/clockevents.c29
-rw-r--r--kernel/time/tick-broadcast.c25
-rw-r--r--kernel/time/tick-internal.h4
3 files changed, 45 insertions, 13 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 086ad6043bcb..641d91003a45 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -439,6 +439,16 @@ void clockevents_config_and_register(struct clock_event_device *dev,
439} 439}
440EXPORT_SYMBOL_GPL(clockevents_config_and_register); 440EXPORT_SYMBOL_GPL(clockevents_config_and_register);
441 441
442int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
443{
444 clockevents_config(dev, freq);
445
446 if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
447 return 0;
448
449 return clockevents_program_event(dev, dev->next_event, false);
450}
451
442/** 452/**
443 * clockevents_update_freq - Update frequency and reprogram a clock event device. 453 * clockevents_update_freq - Update frequency and reprogram a clock event device.
444 * @dev: device to modify 454 * @dev: device to modify
@@ -446,17 +456,22 @@ EXPORT_SYMBOL_GPL(clockevents_config_and_register);
446 * 456 *
447 * Reconfigure and reprogram a clock event device in oneshot 457 * Reconfigure and reprogram a clock event device in oneshot
448 * mode. Must be called on the cpu for which the device delivers per 458 * mode. Must be called on the cpu for which the device delivers per
449 * cpu timer events with interrupts disabled! Returns 0 on success, 459 * cpu timer events. If called for the broadcast device the core takes
450 * -ETIME when the event is in the past. 460 * care of serialization.
461 *
462 * Returns 0 on success, -ETIME when the event is in the past.
451 */ 463 */
452int clockevents_update_freq(struct clock_event_device *dev, u32 freq) 464int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
453{ 465{
454 clockevents_config(dev, freq); 466 unsigned long flags;
455 467 int ret;
456 if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
457 return 0;
458 468
459 return clockevents_program_event(dev, dev->next_event, false); 469 local_irq_save(flags);
470 ret = tick_broadcast_update_freq(dev, freq);
471 if (ret == -ENODEV)
472 ret = __clockevents_update_freq(dev, freq);
473 local_irq_restore(flags);
474 return ret;
460} 475}
461 476
462/* 477/*
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 43780ab5e279..003e6c3663b1 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -120,6 +120,19 @@ int tick_is_broadcast_device(struct clock_event_device *dev)
120 return (dev && tick_broadcast_device.evtdev == dev); 120 return (dev && tick_broadcast_device.evtdev == dev);
121} 121}
122 122
123int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq)
124{
125 int ret = -ENODEV;
126
127 if (tick_is_broadcast_device(dev)) {
128 raw_spin_lock(&tick_broadcast_lock);
129 ret = __clockevents_update_freq(dev, freq);
130 raw_spin_unlock(&tick_broadcast_lock);
131 }
132 return ret;
133}
134
135
123static void err_broadcast(const struct cpumask *mask) 136static void err_broadcast(const struct cpumask *mask)
124{ 137{
125 pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n"); 138 pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
@@ -272,12 +285,8 @@ static void tick_do_broadcast(struct cpumask *mask)
272 */ 285 */
273static void tick_do_periodic_broadcast(void) 286static void tick_do_periodic_broadcast(void)
274{ 287{
275 raw_spin_lock(&tick_broadcast_lock);
276
277 cpumask_and(tmpmask, cpu_online_mask, tick_broadcast_mask); 288 cpumask_and(tmpmask, cpu_online_mask, tick_broadcast_mask);
278 tick_do_broadcast(tmpmask); 289 tick_do_broadcast(tmpmask);
279
280 raw_spin_unlock(&tick_broadcast_lock);
281} 290}
282 291
283/* 292/*
@@ -287,13 +296,15 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
287{ 296{
288 ktime_t next; 297 ktime_t next;
289 298
299 raw_spin_lock(&tick_broadcast_lock);
300
290 tick_do_periodic_broadcast(); 301 tick_do_periodic_broadcast();
291 302
292 /* 303 /*
293 * The device is in periodic mode. No reprogramming necessary: 304 * The device is in periodic mode. No reprogramming necessary:
294 */ 305 */
295 if (dev->mode == CLOCK_EVT_MODE_PERIODIC) 306 if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
296 return; 307 goto unlock;
297 308
298 /* 309 /*
299 * Setup the next period for devices, which do not have 310 * Setup the next period for devices, which do not have
@@ -306,9 +317,11 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
306 next = ktime_add(next, tick_period); 317 next = ktime_add(next, tick_period);
307 318
308 if (!clockevents_program_event(dev, next, false)) 319 if (!clockevents_program_event(dev, next, false))
309 return; 320 goto unlock;
310 tick_do_periodic_broadcast(); 321 tick_do_periodic_broadcast();
311 } 322 }
323unlock:
324 raw_spin_unlock(&tick_broadcast_lock);
312} 325}
313 326
314/* 327/*
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 8329669b51ec..26f1c0ba9d81 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -111,6 +111,7 @@ extern int tick_resume_broadcast(void);
111extern void tick_broadcast_init(void); 111extern void tick_broadcast_init(void);
112extern void 112extern void
113tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); 113tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
114int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
114 115
115#else /* !BROADCAST */ 116#else /* !BROADCAST */
116 117
@@ -133,6 +134,8 @@ static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
133static inline void tick_suspend_broadcast(void) { } 134static inline void tick_suspend_broadcast(void) { }
134static inline int tick_resume_broadcast(void) { return 0; } 135static inline int tick_resume_broadcast(void) { return 0; }
135static inline void tick_broadcast_init(void) { } 136static inline void tick_broadcast_init(void) { }
137static inline int tick_broadcast_update_freq(struct clock_event_device *dev,
138 u32 freq) { return -ENODEV; }
136 139
137/* 140/*
138 * Set the periodic handler in non broadcast mode 141 * Set the periodic handler in non broadcast mode
@@ -154,5 +157,6 @@ static inline int tick_device_is_functional(struct clock_event_device *dev)
154 157
155#endif 158#endif
156 159
160int __clockevents_update_freq(struct clock_event_device *dev, u32 freq);
157extern void do_timer(unsigned long ticks); 161extern void do_timer(unsigned long ticks);
158extern void update_wall_time(void); 162extern void update_wall_time(void);