aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/clockevents.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/clockevents.c')
-rw-r--r--kernel/time/clockevents.c129
1 files changed, 115 insertions, 14 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index e4c699dfa4e8..1ecd6ba36d6c 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -94,42 +94,143 @@ void clockevents_shutdown(struct clock_event_device *dev)
94 dev->next_event.tv64 = KTIME_MAX; 94 dev->next_event.tv64 = KTIME_MAX;
95} 95}
96 96
97#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST
98
99/* Limit min_delta to a jiffie */
100#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ)
101
102/**
103 * clockevents_increase_min_delta - raise minimum delta of a clock event device
104 * @dev: device to increase the minimum delta
105 *
106 * Returns 0 on success, -ETIME when the minimum delta reached the limit.
107 */
108static int clockevents_increase_min_delta(struct clock_event_device *dev)
109{
110 /* Nothing to do if we already reached the limit */
111 if (dev->min_delta_ns >= MIN_DELTA_LIMIT) {
112 printk(KERN_WARNING "CE: Reprogramming failure. Giving up\n");
113 dev->next_event.tv64 = KTIME_MAX;
114 return -ETIME;
115 }
116
117 if (dev->min_delta_ns < 5000)
118 dev->min_delta_ns = 5000;
119 else
120 dev->min_delta_ns += dev->min_delta_ns >> 1;
121
122 if (dev->min_delta_ns > MIN_DELTA_LIMIT)
123 dev->min_delta_ns = MIN_DELTA_LIMIT;
124
125 printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n",
126 dev->name ? dev->name : "?",
127 (unsigned long long) dev->min_delta_ns);
128 return 0;
129}
130
131/**
132 * clockevents_program_min_delta - Set clock event device to the minimum delay.
133 * @dev: device to program
134 *
135 * Returns 0 on success, -ETIME when the retry loop failed.
136 */
137static int clockevents_program_min_delta(struct clock_event_device *dev)
138{
139 unsigned long long clc;
140 int64_t delta;
141 int i;
142
143 for (i = 0;;) {
144 delta = dev->min_delta_ns;
145 dev->next_event = ktime_add_ns(ktime_get(), delta);
146
147 if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
148 return 0;
149
150 dev->retries++;
151 clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
152 if (dev->set_next_event((unsigned long) clc, dev) == 0)
153 return 0;
154
155 if (++i > 2) {
156 /*
157 * We tried 3 times to program the device with the
158 * given min_delta_ns. Try to increase the minimum
159 * delta, if that fails as well get out of here.
160 */
161 if (clockevents_increase_min_delta(dev))
162 return -ETIME;
163 i = 0;
164 }
165 }
166}
167
168#else /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */
169
170/**
171 * clockevents_program_min_delta - Set clock event device to the minimum delay.
172 * @dev: device to program
173 *
174 * Returns 0 on success, -ETIME when the retry loop failed.
175 */
176static int clockevents_program_min_delta(struct clock_event_device *dev)
177{
178 unsigned long long clc;
179 int64_t delta;
180
181 delta = dev->min_delta_ns;
182 dev->next_event = ktime_add_ns(ktime_get(), delta);
183
184 if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
185 return 0;
186
187 dev->retries++;
188 clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
189 return dev->set_next_event((unsigned long) clc, dev);
190}
191
192#endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */
193
97/** 194/**
98 * clockevents_program_event - Reprogram the clock event device. 195 * clockevents_program_event - Reprogram the clock event device.
196 * @dev: device to program
99 * @expires: absolute expiry time (monotonic clock) 197 * @expires: absolute expiry time (monotonic clock)
198 * @force: program minimum delay if expires can not be set
100 * 199 *
101 * Returns 0 on success, -ETIME when the event is in the past. 200 * Returns 0 on success, -ETIME when the event is in the past.
102 */ 201 */
103int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, 202int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
104 ktime_t now) 203 bool force)
105{ 204{
106 unsigned long long clc; 205 unsigned long long clc;
107 int64_t delta; 206 int64_t delta;
207 int rc;
108 208
109 if (unlikely(expires.tv64 < 0)) { 209 if (unlikely(expires.tv64 < 0)) {
110 WARN_ON_ONCE(1); 210 WARN_ON_ONCE(1);
111 return -ETIME; 211 return -ETIME;
112 } 212 }
113 213
114 delta = ktime_to_ns(ktime_sub(expires, now));
115
116 if (delta <= 0)
117 return -ETIME;
118
119 dev->next_event = expires; 214 dev->next_event = expires;
120 215
121 if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN) 216 if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
122 return 0; 217 return 0;
123 218
124 if (delta > dev->max_delta_ns) 219 /* Shortcut for clockevent devices that can deal with ktime. */
125 delta = dev->max_delta_ns; 220 if (dev->features & CLOCK_EVT_FEAT_KTIME)
126 if (delta < dev->min_delta_ns) 221 return dev->set_next_ktime(expires, dev);
127 delta = dev->min_delta_ns; 222
223 delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
224 if (delta <= 0)
225 return force ? clockevents_program_min_delta(dev) : -ETIME;
128 226
129 clc = delta * dev->mult; 227 delta = min(delta, (int64_t) dev->max_delta_ns);
130 clc >>= dev->shift; 228 delta = max(delta, (int64_t) dev->min_delta_ns);
131 229
132 return dev->set_next_event((unsigned long) clc, dev); 230 clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
231 rc = dev->set_next_event((unsigned long) clc, dev);
232
233 return (rc && force) ? clockevents_program_min_delta(dev) : rc;
133} 234}
134 235
135/** 236/**
@@ -258,7 +359,7 @@ int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
258 if (dev->mode != CLOCK_EVT_MODE_ONESHOT) 359 if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
259 return 0; 360 return 0;
260 361
261 return clockevents_program_event(dev, dev->next_event, ktime_get()); 362 return clockevents_program_event(dev, dev->next_event, false);
262} 363}
263 364
264/* 365/*