aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/time/tick-broadcast.c12
-rw-r--r--kernel/time/tick-internal.h2
-rw-r--r--kernel/time/tick-oneshot.c36
3 files changed, 34 insertions, 16 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 5744f40b269..2bc1f046151 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -372,16 +372,8 @@ cpumask_t *tick_get_broadcast_oneshot_mask(void)
372static int tick_broadcast_set_event(ktime_t expires, int force) 372static int tick_broadcast_set_event(ktime_t expires, int force)
373{ 373{
374 struct clock_event_device *bc = tick_broadcast_device.evtdev; 374 struct clock_event_device *bc = tick_broadcast_device.evtdev;
375 ktime_t now = ktime_get(); 375
376 int res; 376 return tick_dev_program_event(bc, expires, force);
377
378 for(;;) {
379 res = clockevents_program_event(bc, expires, now);
380 if (!res || !force)
381 return res;
382 now = ktime_get();
383 expires = ktime_add(now, ktime_set(0, bc->min_delta_ns));
384 }
385} 377}
386 378
387int tick_resume_broadcast_oneshot(struct clock_event_device *bc) 379int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index f13f2b7f4fd..0ffc2918ea6 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct clock_event_device *dev);
17extern void tick_setup_oneshot(struct clock_event_device *newdev, 17extern void tick_setup_oneshot(struct clock_event_device *newdev,
18 void (*handler)(struct clock_event_device *), 18 void (*handler)(struct clock_event_device *),
19 ktime_t nextevt); 19 ktime_t nextevt);
20extern int tick_dev_program_event(struct clock_event_device *dev,
21 ktime_t expires, int force);
20extern int tick_program_event(ktime_t expires, int force); 22extern int tick_program_event(ktime_t expires, int force);
21extern void tick_oneshot_notify(void); 23extern void tick_oneshot_notify(void);
22extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); 24extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index 06595c64b0c..2e35501e61d 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -25,18 +25,42 @@
25/** 25/**
26 * tick_program_event internal worker function 26 * tick_program_event internal worker function
27 */ 27 */
28static int __tick_program_event(struct clock_event_device *dev, 28int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
29 ktime_t expires, int force) 29 int force)
30{ 30{
31 ktime_t now = ktime_get(); 31 ktime_t now = ktime_get();
32 int i;
32 33
33 while (1) { 34 for (i = 0;;) {
34 int ret = clockevents_program_event(dev, expires, now); 35 int ret = clockevents_program_event(dev, expires, now);
35 36
36 if (!ret || !force) 37 if (!ret || !force)
37 return ret; 38 return ret;
39
40 /*
41 * We tried 2 times to program the device with the given
42 * min_delta_ns. If that's not working then we double it
43 * and emit a warning.
44 */
45 if (++i > 2) {
46 printk(KERN_WARNING "CE: __tick_program_event of %s is "
47 "stuck %llx %llx\n", dev->name ? dev->name : "?",
48 now.tv64, expires.tv64);
49 printk(KERN_WARNING
50 "CE: increasing min_delta_ns %ld to %ld nsec\n",
51 dev->min_delta_ns, dev->min_delta_ns << 1);
52 WARN_ON(1);
53
54 /* Double the min. delta and try again */
55 if (!dev->min_delta_ns)
56 dev->min_delta_ns = 5000;
57 else
58 dev->min_delta_ns <<= 1;
59 i = 0;
60 }
61
38 now = ktime_get(); 62 now = ktime_get();
39 expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); 63 expires = ktime_add_ns(now, dev->min_delta_ns);
40 } 64 }
41} 65}
42 66
@@ -47,7 +71,7 @@ int tick_program_event(ktime_t expires, int force)
47{ 71{
48 struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; 72 struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
49 73
50 return __tick_program_event(dev, expires, force); 74 return tick_dev_program_event(dev, expires, force);
51} 75}
52 76
53/** 77/**
@@ -71,7 +95,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
71{ 95{
72 newdev->event_handler = handler; 96 newdev->event_handler = handler;
73 clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); 97 clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
74 __tick_program_event(newdev, next_event, 1); 98 tick_dev_program_event(newdev, next_event, 1);
75} 99}
76 100
77/** 101/**