diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/tick-broadcast.c | 12 | ||||
-rw-r--r-- | kernel/time/tick-internal.h | 2 | ||||
-rw-r--r-- | kernel/time/tick-oneshot.c | 36 |
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) | |||
372 | static int tick_broadcast_set_event(ktime_t expires, int force) | 372 | static 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 | ||
387 | int tick_resume_broadcast_oneshot(struct clock_event_device *bc) | 379 | int 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); | |||
17 | extern void tick_setup_oneshot(struct clock_event_device *newdev, | 17 | extern 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); |
20 | extern int tick_dev_program_event(struct clock_event_device *dev, | ||
21 | ktime_t expires, int force); | ||
20 | extern int tick_program_event(ktime_t expires, int force); | 22 | extern int tick_program_event(ktime_t expires, int force); |
21 | extern void tick_oneshot_notify(void); | 23 | extern void tick_oneshot_notify(void); |
22 | extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); | 24 | extern 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 | */ |
28 | static int __tick_program_event(struct clock_event_device *dev, | 28 | int 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 | /** |