diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-08-23 09:29:42 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-09-08 05:10:56 -0400 |
commit | d1748302f70be7469809809283fe164156a34231 (patch) | |
tree | c81137f4126f2fe1451c28441415c1cd0fa0f7cd /kernel/time/tick-oneshot.c | |
parent | 29c158e81c733ac7d6a75c5ee929f34fb9f92983 (diff) |
clockevents: Make minimum delay adjustments configurable
The automatic increase of the min_delta_ns of a clockevents device
should be done in the clockevents code as the minimum delay is an
attribute of the clockevents device.
In addition not all architectures want the automatic adjustment, on a
massively virtualized system it can happen that the programming of a
clock event fails several times in a row because the virtual cpu has
been rescheduled quickly enough. In that case the minimum delay will
erroneously be increased with no way back. The new config symbol
GENERIC_CLOCKEVENTS_MIN_ADJUST is used to enable the automatic
adjustment. The config option is selected only for x86.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: john stultz <johnstul@us.ibm.com>
Link: http://lkml.kernel.org/r/20110823133142.494157493@de.ibm.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/tick-oneshot.c')
-rw-r--r-- | kernel/time/tick-oneshot.c | 77 |
1 files changed, 4 insertions, 73 deletions
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 2d04411a5f05..824109060a33 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
@@ -21,74 +21,6 @@ | |||
21 | 21 | ||
22 | #include "tick-internal.h" | 22 | #include "tick-internal.h" |
23 | 23 | ||
24 | /* Limit min_delta to a jiffie */ | ||
25 | #define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) | ||
26 | |||
27 | static int tick_increase_min_delta(struct clock_event_device *dev) | ||
28 | { | ||
29 | /* Nothing to do if we already reached the limit */ | ||
30 | if (dev->min_delta_ns >= MIN_DELTA_LIMIT) | ||
31 | return -ETIME; | ||
32 | |||
33 | if (dev->min_delta_ns < 5000) | ||
34 | dev->min_delta_ns = 5000; | ||
35 | else | ||
36 | dev->min_delta_ns += dev->min_delta_ns >> 1; | ||
37 | |||
38 | if (dev->min_delta_ns > MIN_DELTA_LIMIT) | ||
39 | dev->min_delta_ns = MIN_DELTA_LIMIT; | ||
40 | |||
41 | printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", | ||
42 | dev->name ? dev->name : "?", | ||
43 | (unsigned long long) dev->min_delta_ns); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * tick_program_event internal worker function | ||
49 | */ | ||
50 | int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, | ||
51 | int force) | ||
52 | { | ||
53 | ktime_t now = ktime_get(); | ||
54 | int i; | ||
55 | |||
56 | for (i = 0;;) { | ||
57 | int ret = clockevents_program_event(dev, expires, now); | ||
58 | |||
59 | if (!ret || !force) | ||
60 | return ret; | ||
61 | |||
62 | dev->retries++; | ||
63 | /* | ||
64 | * We tried 3 times to program the device with the given | ||
65 | * min_delta_ns. If that's not working then we increase it | ||
66 | * and emit a warning. | ||
67 | */ | ||
68 | if (++i > 2) { | ||
69 | /* Increase the min. delta and try again */ | ||
70 | if (tick_increase_min_delta(dev)) { | ||
71 | /* | ||
72 | * Get out of the loop if min_delta_ns | ||
73 | * hit the limit already. That's | ||
74 | * better than staying here forever. | ||
75 | * | ||
76 | * We clear next_event so we have a | ||
77 | * chance that the box survives. | ||
78 | */ | ||
79 | printk(KERN_WARNING | ||
80 | "CE: Reprogramming failure. Giving up\n"); | ||
81 | dev->next_event.tv64 = KTIME_MAX; | ||
82 | return -ETIME; | ||
83 | } | ||
84 | i = 0; | ||
85 | } | ||
86 | |||
87 | now = ktime_get(); | ||
88 | expires = ktime_add_ns(now, dev->min_delta_ns); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /** | 24 | /** |
93 | * tick_program_event | 25 | * tick_program_event |
94 | */ | 26 | */ |
@@ -96,7 +28,7 @@ int tick_program_event(ktime_t expires, int force) | |||
96 | { | 28 | { |
97 | struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); | 29 | struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); |
98 | 30 | ||
99 | return tick_dev_program_event(dev, expires, force); | 31 | return clockevents_program_event(dev, expires, force); |
100 | } | 32 | } |
101 | 33 | ||
102 | /** | 34 | /** |
@@ -104,11 +36,10 @@ int tick_program_event(ktime_t expires, int force) | |||
104 | */ | 36 | */ |
105 | void tick_resume_oneshot(void) | 37 | void tick_resume_oneshot(void) |
106 | { | 38 | { |
107 | struct tick_device *td = &__get_cpu_var(tick_cpu_device); | 39 | struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); |
108 | struct clock_event_device *dev = td->evtdev; | ||
109 | 40 | ||
110 | clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); | 41 | clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); |
111 | tick_program_event(ktime_get(), 1); | 42 | clockevents_program_event(dev, ktime_get(), true); |
112 | } | 43 | } |
113 | 44 | ||
114 | /** | 45 | /** |
@@ -120,7 +51,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, | |||
120 | { | 51 | { |
121 | newdev->event_handler = handler; | 52 | newdev->event_handler = handler; |
122 | clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); | 53 | clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); |
123 | tick_dev_program_event(newdev, next_event, 1); | 54 | clockevents_program_event(newdev, next_event, true); |
124 | } | 55 | } |
125 | 56 | ||
126 | /** | 57 | /** |