diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/Makefile | 3 | ||||
-rw-r--r-- | kernel/time/clockevents.c | 1 | ||||
-rw-r--r-- | kernel/time/jiffies.c | 22 | ||||
-rw-r--r-- | kernel/time/ntp.c | 15 | ||||
-rw-r--r-- | kernel/time/posix-clock.c | 445 | ||||
-rw-r--r-- | kernel/time/tick-broadcast.c | 11 | ||||
-rw-r--r-- | kernel/time/tick-common.c | 7 | ||||
-rw-r--r-- | kernel/time/tick-internal.h | 12 | ||||
-rw-r--r-- | kernel/time/tick-oneshot.c | 1 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 1 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 168 | ||||
-rw-r--r-- | kernel/time/timer_stats.c | 2 |
12 files changed, 652 insertions, 36 deletions
diff --git a/kernel/time/Makefile b/kernel/time/Makefile index ee266620b06c..b0425991e9ac 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o timeconv.o | 1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o |
2 | obj-y += timeconv.o posix-clock.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o | 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o |
4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o | 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o |
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index d7395fdfb9f3..0d74b9ba90c8 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/notifier.h> | 18 | #include <linux/notifier.h> |
19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
20 | #include <linux/sysdev.h> | 20 | #include <linux/sysdev.h> |
21 | #include <linux/tick.h> | ||
22 | 21 | ||
23 | #include "tick-internal.h" | 22 | #include "tick-internal.h" |
24 | 23 | ||
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index 5404a8456909..a470154e0408 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c | |||
@@ -22,8 +22,11 @@ | |||
22 | ************************************************************************/ | 22 | ************************************************************************/ |
23 | #include <linux/clocksource.h> | 23 | #include <linux/clocksource.h> |
24 | #include <linux/jiffies.h> | 24 | #include <linux/jiffies.h> |
25 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
26 | 27 | ||
28 | #include "tick-internal.h" | ||
29 | |||
27 | /* The Jiffies based clocksource is the lowest common | 30 | /* The Jiffies based clocksource is the lowest common |
28 | * denominator clock source which should function on | 31 | * denominator clock source which should function on |
29 | * all systems. It has the same coarse resolution as | 32 | * all systems. It has the same coarse resolution as |
@@ -31,7 +34,7 @@ | |||
31 | * inaccuracies caused by missed or lost timer | 34 | * inaccuracies caused by missed or lost timer |
32 | * interrupts and the inability for the timer | 35 | * interrupts and the inability for the timer |
33 | * interrupt hardware to accuratly tick at the | 36 | * interrupt hardware to accuratly tick at the |
34 | * requested HZ value. It is also not reccomended | 37 | * requested HZ value. It is also not recommended |
35 | * for "tick-less" systems. | 38 | * for "tick-less" systems. |
36 | */ | 39 | */ |
37 | #define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ)) | 40 | #define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ)) |
@@ -64,6 +67,23 @@ struct clocksource clocksource_jiffies = { | |||
64 | .shift = JIFFIES_SHIFT, | 67 | .shift = JIFFIES_SHIFT, |
65 | }; | 68 | }; |
66 | 69 | ||
70 | #if (BITS_PER_LONG < 64) | ||
71 | u64 get_jiffies_64(void) | ||
72 | { | ||
73 | unsigned long seq; | ||
74 | u64 ret; | ||
75 | |||
76 | do { | ||
77 | seq = read_seqbegin(&xtime_lock); | ||
78 | ret = jiffies_64; | ||
79 | } while (read_seqretry(&xtime_lock, seq)); | ||
80 | return ret; | ||
81 | } | ||
82 | EXPORT_SYMBOL(get_jiffies_64); | ||
83 | #endif | ||
84 | |||
85 | EXPORT_SYMBOL(jiffies); | ||
86 | |||
67 | static int __init init_jiffies_clocksource(void) | 87 | static int __init init_jiffies_clocksource(void) |
68 | { | 88 | { |
69 | return clocksource_register(&clocksource_jiffies); | 89 | return clocksource_register(&clocksource_jiffies); |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 5c00242fa921..f6117a4c7cb8 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | ||
19 | #include "tick-internal.h" | ||
20 | |||
19 | /* | 21 | /* |
20 | * NTP timekeeping variables: | 22 | * NTP timekeeping variables: |
21 | */ | 23 | */ |
@@ -646,6 +648,19 @@ int do_adjtimex(struct timex *txc) | |||
646 | hrtimer_cancel(&leap_timer); | 648 | hrtimer_cancel(&leap_timer); |
647 | } | 649 | } |
648 | 650 | ||
651 | if (txc->modes & ADJ_SETOFFSET) { | ||
652 | struct timespec delta; | ||
653 | delta.tv_sec = txc->time.tv_sec; | ||
654 | delta.tv_nsec = txc->time.tv_usec; | ||
655 | if (!capable(CAP_SYS_TIME)) | ||
656 | return -EPERM; | ||
657 | if (!(txc->modes & ADJ_NANO)) | ||
658 | delta.tv_nsec *= 1000; | ||
659 | result = timekeeping_inject_offset(&delta); | ||
660 | if (result) | ||
661 | return result; | ||
662 | } | ||
663 | |||
649 | getnstimeofday(&ts); | 664 | getnstimeofday(&ts); |
650 | 665 | ||
651 | write_seqlock_irq(&xtime_lock); | 666 | write_seqlock_irq(&xtime_lock); |
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c new file mode 100644 index 000000000000..c340ca658f37 --- /dev/null +++ b/kernel/time/posix-clock.c | |||
@@ -0,0 +1,445 @@ | |||
1 | /* | ||
2 | * posix-clock.c - support for dynamic clock devices | ||
3 | * | ||
4 | * Copyright (C) 2010 OMICRON electronics GmbH | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/file.h> | ||
22 | #include <linux/posix-clock.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/syscalls.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | |||
27 | static void delete_clock(struct kref *kref); | ||
28 | |||
29 | /* | ||
30 | * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. | ||
31 | */ | ||
32 | static struct posix_clock *get_posix_clock(struct file *fp) | ||
33 | { | ||
34 | struct posix_clock *clk = fp->private_data; | ||
35 | |||
36 | down_read(&clk->rwsem); | ||
37 | |||
38 | if (!clk->zombie) | ||
39 | return clk; | ||
40 | |||
41 | up_read(&clk->rwsem); | ||
42 | |||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | static void put_posix_clock(struct posix_clock *clk) | ||
47 | { | ||
48 | up_read(&clk->rwsem); | ||
49 | } | ||
50 | |||
51 | static ssize_t posix_clock_read(struct file *fp, char __user *buf, | ||
52 | size_t count, loff_t *ppos) | ||
53 | { | ||
54 | struct posix_clock *clk = get_posix_clock(fp); | ||
55 | int err = -EINVAL; | ||
56 | |||
57 | if (!clk) | ||
58 | return -ENODEV; | ||
59 | |||
60 | if (clk->ops.read) | ||
61 | err = clk->ops.read(clk, fp->f_flags, buf, count); | ||
62 | |||
63 | put_posix_clock(clk); | ||
64 | |||
65 | return err; | ||
66 | } | ||
67 | |||
68 | static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) | ||
69 | { | ||
70 | struct posix_clock *clk = get_posix_clock(fp); | ||
71 | int result = 0; | ||
72 | |||
73 | if (!clk) | ||
74 | return -ENODEV; | ||
75 | |||
76 | if (clk->ops.poll) | ||
77 | result = clk->ops.poll(clk, fp, wait); | ||
78 | |||
79 | put_posix_clock(clk); | ||
80 | |||
81 | return result; | ||
82 | } | ||
83 | |||
84 | static int posix_clock_fasync(int fd, struct file *fp, int on) | ||
85 | { | ||
86 | struct posix_clock *clk = get_posix_clock(fp); | ||
87 | int err = 0; | ||
88 | |||
89 | if (!clk) | ||
90 | return -ENODEV; | ||
91 | |||
92 | if (clk->ops.fasync) | ||
93 | err = clk->ops.fasync(clk, fd, fp, on); | ||
94 | |||
95 | put_posix_clock(clk); | ||
96 | |||
97 | return err; | ||
98 | } | ||
99 | |||
100 | static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) | ||
101 | { | ||
102 | struct posix_clock *clk = get_posix_clock(fp); | ||
103 | int err = -ENODEV; | ||
104 | |||
105 | if (!clk) | ||
106 | return -ENODEV; | ||
107 | |||
108 | if (clk->ops.mmap) | ||
109 | err = clk->ops.mmap(clk, vma); | ||
110 | |||
111 | put_posix_clock(clk); | ||
112 | |||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static long posix_clock_ioctl(struct file *fp, | ||
117 | unsigned int cmd, unsigned long arg) | ||
118 | { | ||
119 | struct posix_clock *clk = get_posix_clock(fp); | ||
120 | int err = -ENOTTY; | ||
121 | |||
122 | if (!clk) | ||
123 | return -ENODEV; | ||
124 | |||
125 | if (clk->ops.ioctl) | ||
126 | err = clk->ops.ioctl(clk, cmd, arg); | ||
127 | |||
128 | put_posix_clock(clk); | ||
129 | |||
130 | return err; | ||
131 | } | ||
132 | |||
133 | #ifdef CONFIG_COMPAT | ||
134 | static long posix_clock_compat_ioctl(struct file *fp, | ||
135 | unsigned int cmd, unsigned long arg) | ||
136 | { | ||
137 | struct posix_clock *clk = get_posix_clock(fp); | ||
138 | int err = -ENOTTY; | ||
139 | |||
140 | if (!clk) | ||
141 | return -ENODEV; | ||
142 | |||
143 | if (clk->ops.ioctl) | ||
144 | err = clk->ops.ioctl(clk, cmd, arg); | ||
145 | |||
146 | put_posix_clock(clk); | ||
147 | |||
148 | return err; | ||
149 | } | ||
150 | #endif | ||
151 | |||
152 | static int posix_clock_open(struct inode *inode, struct file *fp) | ||
153 | { | ||
154 | int err; | ||
155 | struct posix_clock *clk = | ||
156 | container_of(inode->i_cdev, struct posix_clock, cdev); | ||
157 | |||
158 | down_read(&clk->rwsem); | ||
159 | |||
160 | if (clk->zombie) { | ||
161 | err = -ENODEV; | ||
162 | goto out; | ||
163 | } | ||
164 | if (clk->ops.open) | ||
165 | err = clk->ops.open(clk, fp->f_mode); | ||
166 | else | ||
167 | err = 0; | ||
168 | |||
169 | if (!err) { | ||
170 | kref_get(&clk->kref); | ||
171 | fp->private_data = clk; | ||
172 | } | ||
173 | out: | ||
174 | up_read(&clk->rwsem); | ||
175 | return err; | ||
176 | } | ||
177 | |||
178 | static int posix_clock_release(struct inode *inode, struct file *fp) | ||
179 | { | ||
180 | struct posix_clock *clk = fp->private_data; | ||
181 | int err = 0; | ||
182 | |||
183 | if (clk->ops.release) | ||
184 | err = clk->ops.release(clk); | ||
185 | |||
186 | kref_put(&clk->kref, delete_clock); | ||
187 | |||
188 | fp->private_data = NULL; | ||
189 | |||
190 | return err; | ||
191 | } | ||
192 | |||
193 | static const struct file_operations posix_clock_file_operations = { | ||
194 | .owner = THIS_MODULE, | ||
195 | .llseek = no_llseek, | ||
196 | .read = posix_clock_read, | ||
197 | .poll = posix_clock_poll, | ||
198 | .unlocked_ioctl = posix_clock_ioctl, | ||
199 | .open = posix_clock_open, | ||
200 | .release = posix_clock_release, | ||
201 | .fasync = posix_clock_fasync, | ||
202 | .mmap = posix_clock_mmap, | ||
203 | #ifdef CONFIG_COMPAT | ||
204 | .compat_ioctl = posix_clock_compat_ioctl, | ||
205 | #endif | ||
206 | }; | ||
207 | |||
208 | int posix_clock_register(struct posix_clock *clk, dev_t devid) | ||
209 | { | ||
210 | int err; | ||
211 | |||
212 | kref_init(&clk->kref); | ||
213 | init_rwsem(&clk->rwsem); | ||
214 | |||
215 | cdev_init(&clk->cdev, &posix_clock_file_operations); | ||
216 | clk->cdev.owner = clk->ops.owner; | ||
217 | err = cdev_add(&clk->cdev, devid, 1); | ||
218 | |||
219 | return err; | ||
220 | } | ||
221 | EXPORT_SYMBOL_GPL(posix_clock_register); | ||
222 | |||
223 | static void delete_clock(struct kref *kref) | ||
224 | { | ||
225 | struct posix_clock *clk = container_of(kref, struct posix_clock, kref); | ||
226 | |||
227 | if (clk->release) | ||
228 | clk->release(clk); | ||
229 | } | ||
230 | |||
231 | void posix_clock_unregister(struct posix_clock *clk) | ||
232 | { | ||
233 | cdev_del(&clk->cdev); | ||
234 | |||
235 | down_write(&clk->rwsem); | ||
236 | clk->zombie = true; | ||
237 | up_write(&clk->rwsem); | ||
238 | |||
239 | kref_put(&clk->kref, delete_clock); | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(posix_clock_unregister); | ||
242 | |||
243 | struct posix_clock_desc { | ||
244 | struct file *fp; | ||
245 | struct posix_clock *clk; | ||
246 | }; | ||
247 | |||
248 | static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd) | ||
249 | { | ||
250 | struct file *fp = fget(CLOCKID_TO_FD(id)); | ||
251 | int err = -EINVAL; | ||
252 | |||
253 | if (!fp) | ||
254 | return err; | ||
255 | |||
256 | if (fp->f_op->open != posix_clock_open || !fp->private_data) | ||
257 | goto out; | ||
258 | |||
259 | cd->fp = fp; | ||
260 | cd->clk = get_posix_clock(fp); | ||
261 | |||
262 | err = cd->clk ? 0 : -ENODEV; | ||
263 | out: | ||
264 | if (err) | ||
265 | fput(fp); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static void put_clock_desc(struct posix_clock_desc *cd) | ||
270 | { | ||
271 | put_posix_clock(cd->clk); | ||
272 | fput(cd->fp); | ||
273 | } | ||
274 | |||
275 | static int pc_clock_adjtime(clockid_t id, struct timex *tx) | ||
276 | { | ||
277 | struct posix_clock_desc cd; | ||
278 | int err; | ||
279 | |||
280 | err = get_clock_desc(id, &cd); | ||
281 | if (err) | ||
282 | return err; | ||
283 | |||
284 | if ((cd.fp->f_mode & FMODE_WRITE) == 0) { | ||
285 | err = -EACCES; | ||
286 | goto out; | ||
287 | } | ||
288 | |||
289 | if (cd.clk->ops.clock_adjtime) | ||
290 | err = cd.clk->ops.clock_adjtime(cd.clk, tx); | ||
291 | else | ||
292 | err = -EOPNOTSUPP; | ||
293 | out: | ||
294 | put_clock_desc(&cd); | ||
295 | |||
296 | return err; | ||
297 | } | ||
298 | |||
299 | static int pc_clock_gettime(clockid_t id, struct timespec *ts) | ||
300 | { | ||
301 | struct posix_clock_desc cd; | ||
302 | int err; | ||
303 | |||
304 | err = get_clock_desc(id, &cd); | ||
305 | if (err) | ||
306 | return err; | ||
307 | |||
308 | if (cd.clk->ops.clock_gettime) | ||
309 | err = cd.clk->ops.clock_gettime(cd.clk, ts); | ||
310 | else | ||
311 | err = -EOPNOTSUPP; | ||
312 | |||
313 | put_clock_desc(&cd); | ||
314 | |||
315 | return err; | ||
316 | } | ||
317 | |||
318 | static int pc_clock_getres(clockid_t id, struct timespec *ts) | ||
319 | { | ||
320 | struct posix_clock_desc cd; | ||
321 | int err; | ||
322 | |||
323 | err = get_clock_desc(id, &cd); | ||
324 | if (err) | ||
325 | return err; | ||
326 | |||
327 | if (cd.clk->ops.clock_getres) | ||
328 | err = cd.clk->ops.clock_getres(cd.clk, ts); | ||
329 | else | ||
330 | err = -EOPNOTSUPP; | ||
331 | |||
332 | put_clock_desc(&cd); | ||
333 | |||
334 | return err; | ||
335 | } | ||
336 | |||
337 | static int pc_clock_settime(clockid_t id, const struct timespec *ts) | ||
338 | { | ||
339 | struct posix_clock_desc cd; | ||
340 | int err; | ||
341 | |||
342 | err = get_clock_desc(id, &cd); | ||
343 | if (err) | ||
344 | return err; | ||
345 | |||
346 | if ((cd.fp->f_mode & FMODE_WRITE) == 0) { | ||
347 | err = -EACCES; | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | if (cd.clk->ops.clock_settime) | ||
352 | err = cd.clk->ops.clock_settime(cd.clk, ts); | ||
353 | else | ||
354 | err = -EOPNOTSUPP; | ||
355 | out: | ||
356 | put_clock_desc(&cd); | ||
357 | |||
358 | return err; | ||
359 | } | ||
360 | |||
361 | static int pc_timer_create(struct k_itimer *kit) | ||
362 | { | ||
363 | clockid_t id = kit->it_clock; | ||
364 | struct posix_clock_desc cd; | ||
365 | int err; | ||
366 | |||
367 | err = get_clock_desc(id, &cd); | ||
368 | if (err) | ||
369 | return err; | ||
370 | |||
371 | if (cd.clk->ops.timer_create) | ||
372 | err = cd.clk->ops.timer_create(cd.clk, kit); | ||
373 | else | ||
374 | err = -EOPNOTSUPP; | ||
375 | |||
376 | put_clock_desc(&cd); | ||
377 | |||
378 | return err; | ||
379 | } | ||
380 | |||
381 | static int pc_timer_delete(struct k_itimer *kit) | ||
382 | { | ||
383 | clockid_t id = kit->it_clock; | ||
384 | struct posix_clock_desc cd; | ||
385 | int err; | ||
386 | |||
387 | err = get_clock_desc(id, &cd); | ||
388 | if (err) | ||
389 | return err; | ||
390 | |||
391 | if (cd.clk->ops.timer_delete) | ||
392 | err = cd.clk->ops.timer_delete(cd.clk, kit); | ||
393 | else | ||
394 | err = -EOPNOTSUPP; | ||
395 | |||
396 | put_clock_desc(&cd); | ||
397 | |||
398 | return err; | ||
399 | } | ||
400 | |||
401 | static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) | ||
402 | { | ||
403 | clockid_t id = kit->it_clock; | ||
404 | struct posix_clock_desc cd; | ||
405 | |||
406 | if (get_clock_desc(id, &cd)) | ||
407 | return; | ||
408 | |||
409 | if (cd.clk->ops.timer_gettime) | ||
410 | cd.clk->ops.timer_gettime(cd.clk, kit, ts); | ||
411 | |||
412 | put_clock_desc(&cd); | ||
413 | } | ||
414 | |||
415 | static int pc_timer_settime(struct k_itimer *kit, int flags, | ||
416 | struct itimerspec *ts, struct itimerspec *old) | ||
417 | { | ||
418 | clockid_t id = kit->it_clock; | ||
419 | struct posix_clock_desc cd; | ||
420 | int err; | ||
421 | |||
422 | err = get_clock_desc(id, &cd); | ||
423 | if (err) | ||
424 | return err; | ||
425 | |||
426 | if (cd.clk->ops.timer_settime) | ||
427 | err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); | ||
428 | else | ||
429 | err = -EOPNOTSUPP; | ||
430 | |||
431 | put_clock_desc(&cd); | ||
432 | |||
433 | return err; | ||
434 | } | ||
435 | |||
436 | struct k_clock clock_posix_dynamic = { | ||
437 | .clock_getres = pc_clock_getres, | ||
438 | .clock_set = pc_clock_settime, | ||
439 | .clock_get = pc_clock_gettime, | ||
440 | .clock_adj = pc_clock_adjtime, | ||
441 | .timer_create = pc_timer_create, | ||
442 | .timer_set = pc_timer_settime, | ||
443 | .timer_del = pc_timer_delete, | ||
444 | .timer_get = pc_timer_gettime, | ||
445 | }; | ||
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 48b2761b5668..da800ffa810c 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | #include <linux/profile.h> | 19 | #include <linux/profile.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/tick.h> | ||
22 | 21 | ||
23 | #include "tick-internal.h" | 22 | #include "tick-internal.h" |
24 | 23 | ||
@@ -600,4 +599,14 @@ int tick_broadcast_oneshot_active(void) | |||
600 | return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT; | 599 | return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT; |
601 | } | 600 | } |
602 | 601 | ||
602 | /* | ||
603 | * Check whether the broadcast device supports oneshot. | ||
604 | */ | ||
605 | bool tick_broadcast_oneshot_available(void) | ||
606 | { | ||
607 | struct clock_event_device *bc = tick_broadcast_device.evtdev; | ||
608 | |||
609 | return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false; | ||
610 | } | ||
611 | |||
603 | #endif | 612 | #endif |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 051bc80a0c43..119528de8235 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | #include <linux/profile.h> | 19 | #include <linux/profile.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/tick.h> | ||
22 | 21 | ||
23 | #include <asm/irq_regs.h> | 22 | #include <asm/irq_regs.h> |
24 | 23 | ||
@@ -51,7 +50,11 @@ int tick_is_oneshot_available(void) | |||
51 | { | 50 | { |
52 | struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); | 51 | struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); |
53 | 52 | ||
54 | return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT); | 53 | if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT)) |
54 | return 0; | ||
55 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) | ||
56 | return 1; | ||
57 | return tick_broadcast_oneshot_available(); | ||
55 | } | 58 | } |
56 | 59 | ||
57 | /* | 60 | /* |
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 290eefbc1f60..1009b06d6f89 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h | |||
@@ -1,6 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * tick internal variable and functions used by low/high res code | 2 | * tick internal variable and functions used by low/high res code |
3 | */ | 3 | */ |
4 | #include <linux/hrtimer.h> | ||
5 | #include <linux/tick.h> | ||
6 | |||
7 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD | ||
4 | 8 | ||
5 | #define TICK_DO_TIMER_NONE -1 | 9 | #define TICK_DO_TIMER_NONE -1 |
6 | #define TICK_DO_TIMER_BOOT -2 | 10 | #define TICK_DO_TIMER_BOOT -2 |
@@ -36,6 +40,7 @@ extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); | |||
36 | extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); | 40 | extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); |
37 | extern int tick_broadcast_oneshot_active(void); | 41 | extern int tick_broadcast_oneshot_active(void); |
38 | extern void tick_check_oneshot_broadcast(int cpu); | 42 | extern void tick_check_oneshot_broadcast(int cpu); |
43 | bool tick_broadcast_oneshot_available(void); | ||
39 | # else /* BROADCAST */ | 44 | # else /* BROADCAST */ |
40 | static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | 45 | static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) |
41 | { | 46 | { |
@@ -46,6 +51,7 @@ static inline void tick_broadcast_switch_to_oneshot(void) { } | |||
46 | static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } | 51 | static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } |
47 | static inline int tick_broadcast_oneshot_active(void) { return 0; } | 52 | static inline int tick_broadcast_oneshot_active(void) { return 0; } |
48 | static inline void tick_check_oneshot_broadcast(int cpu) { } | 53 | static inline void tick_check_oneshot_broadcast(int cpu) { } |
54 | static inline bool tick_broadcast_oneshot_available(void) { return true; } | ||
49 | # endif /* !BROADCAST */ | 55 | # endif /* !BROADCAST */ |
50 | 56 | ||
51 | #else /* !ONESHOT */ | 57 | #else /* !ONESHOT */ |
@@ -76,6 +82,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc) | |||
76 | return 0; | 82 | return 0; |
77 | } | 83 | } |
78 | static inline int tick_broadcast_oneshot_active(void) { return 0; } | 84 | static inline int tick_broadcast_oneshot_active(void) { return 0; } |
85 | static inline bool tick_broadcast_oneshot_available(void) { return false; } | ||
79 | #endif /* !TICK_ONESHOT */ | 86 | #endif /* !TICK_ONESHOT */ |
80 | 87 | ||
81 | /* | 88 | /* |
@@ -132,3 +139,8 @@ static inline int tick_device_is_functional(struct clock_event_device *dev) | |||
132 | { | 139 | { |
133 | return !(dev->features & CLOCK_EVT_FEAT_DUMMY); | 140 | return !(dev->features & CLOCK_EVT_FEAT_DUMMY); |
134 | } | 141 | } |
142 | |||
143 | #endif | ||
144 | |||
145 | extern void do_timer(unsigned long ticks); | ||
146 | extern seqlock_t xtime_lock; | ||
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 5cbc101f908b..2d04411a5f05 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | #include <linux/profile.h> | 19 | #include <linux/profile.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/tick.h> | ||
22 | 21 | ||
23 | #include "tick-internal.h" | 22 | #include "tick-internal.h" |
24 | 23 | ||
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index c55ea2433471..d5097c44b407 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/percpu.h> | 19 | #include <linux/percpu.h> |
20 | #include <linux/profile.h> | 20 | #include <linux/profile.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/tick.h> | ||
23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
24 | 23 | ||
25 | #include <asm/irq_regs.h> | 24 | #include <asm/irq_regs.h> |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d27c7562902c..8ad5d576755e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/sysdev.h> | 17 | #include <linux/syscore_ops.h> |
18 | #include <linux/clocksource.h> | 18 | #include <linux/clocksource.h> |
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
@@ -353,7 +353,7 @@ EXPORT_SYMBOL(do_gettimeofday); | |||
353 | * | 353 | * |
354 | * Sets the time of day to the new time and update NTP and notify hrtimers | 354 | * Sets the time of day to the new time and update NTP and notify hrtimers |
355 | */ | 355 | */ |
356 | int do_settimeofday(struct timespec *tv) | 356 | int do_settimeofday(const struct timespec *tv) |
357 | { | 357 | { |
358 | struct timespec ts_delta; | 358 | struct timespec ts_delta; |
359 | unsigned long flags; | 359 | unsigned long flags; |
@@ -387,6 +387,42 @@ int do_settimeofday(struct timespec *tv) | |||
387 | 387 | ||
388 | EXPORT_SYMBOL(do_settimeofday); | 388 | EXPORT_SYMBOL(do_settimeofday); |
389 | 389 | ||
390 | |||
391 | /** | ||
392 | * timekeeping_inject_offset - Adds or subtracts from the current time. | ||
393 | * @tv: pointer to the timespec variable containing the offset | ||
394 | * | ||
395 | * Adds or subtracts an offset value from the current time. | ||
396 | */ | ||
397 | int timekeeping_inject_offset(struct timespec *ts) | ||
398 | { | ||
399 | unsigned long flags; | ||
400 | |||
401 | if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) | ||
402 | return -EINVAL; | ||
403 | |||
404 | write_seqlock_irqsave(&xtime_lock, flags); | ||
405 | |||
406 | timekeeping_forward_now(); | ||
407 | |||
408 | xtime = timespec_add(xtime, *ts); | ||
409 | wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts); | ||
410 | |||
411 | timekeeper.ntp_error = 0; | ||
412 | ntp_clear(); | ||
413 | |||
414 | update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock, | ||
415 | timekeeper.mult); | ||
416 | |||
417 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
418 | |||
419 | /* signal hrtimers about time change */ | ||
420 | clock_was_set(); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | EXPORT_SYMBOL(timekeeping_inject_offset); | ||
425 | |||
390 | /** | 426 | /** |
391 | * change_clocksource - Swaps clocksources if a new one is available | 427 | * change_clocksource - Swaps clocksources if a new one is available |
392 | * | 428 | * |
@@ -561,13 +597,12 @@ static struct timespec timekeeping_suspend_time; | |||
561 | 597 | ||
562 | /** | 598 | /** |
563 | * timekeeping_resume - Resumes the generic timekeeping subsystem. | 599 | * timekeeping_resume - Resumes the generic timekeeping subsystem. |
564 | * @dev: unused | ||
565 | * | 600 | * |
566 | * This is for the generic clocksource timekeeping. | 601 | * This is for the generic clocksource timekeeping. |
567 | * xtime/wall_to_monotonic/jiffies/etc are | 602 | * xtime/wall_to_monotonic/jiffies/etc are |
568 | * still managed by arch specific suspend/resume code. | 603 | * still managed by arch specific suspend/resume code. |
569 | */ | 604 | */ |
570 | static int timekeeping_resume(struct sys_device *dev) | 605 | static void timekeeping_resume(void) |
571 | { | 606 | { |
572 | unsigned long flags; | 607 | unsigned long flags; |
573 | struct timespec ts; | 608 | struct timespec ts; |
@@ -596,11 +631,9 @@ static int timekeeping_resume(struct sys_device *dev) | |||
596 | 631 | ||
597 | /* Resume hrtimers */ | 632 | /* Resume hrtimers */ |
598 | hres_timers_resume(); | 633 | hres_timers_resume(); |
599 | |||
600 | return 0; | ||
601 | } | 634 | } |
602 | 635 | ||
603 | static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | 636 | static int timekeeping_suspend(void) |
604 | { | 637 | { |
605 | unsigned long flags; | 638 | unsigned long flags; |
606 | 639 | ||
@@ -618,26 +651,18 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | |||
618 | } | 651 | } |
619 | 652 | ||
620 | /* sysfs resume/suspend bits for timekeeping */ | 653 | /* sysfs resume/suspend bits for timekeeping */ |
621 | static struct sysdev_class timekeeping_sysclass = { | 654 | static struct syscore_ops timekeeping_syscore_ops = { |
622 | .name = "timekeeping", | ||
623 | .resume = timekeeping_resume, | 655 | .resume = timekeeping_resume, |
624 | .suspend = timekeeping_suspend, | 656 | .suspend = timekeeping_suspend, |
625 | }; | 657 | }; |
626 | 658 | ||
627 | static struct sys_device device_timer = { | 659 | static int __init timekeeping_init_ops(void) |
628 | .id = 0, | ||
629 | .cls = &timekeeping_sysclass, | ||
630 | }; | ||
631 | |||
632 | static int __init timekeeping_init_device(void) | ||
633 | { | 660 | { |
634 | int error = sysdev_class_register(&timekeeping_sysclass); | 661 | register_syscore_ops(&timekeeping_syscore_ops); |
635 | if (!error) | 662 | return 0; |
636 | error = sysdev_register(&device_timer); | ||
637 | return error; | ||
638 | } | 663 | } |
639 | 664 | ||
640 | device_initcall(timekeeping_init_device); | 665 | device_initcall(timekeeping_init_ops); |
641 | 666 | ||
642 | /* | 667 | /* |
643 | * If the error is already larger, we look ahead even further | 668 | * If the error is already larger, we look ahead even further |
@@ -779,7 +804,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) | |||
779 | * | 804 | * |
780 | * Called from the timer interrupt, must hold a write on xtime_lock. | 805 | * Called from the timer interrupt, must hold a write on xtime_lock. |
781 | */ | 806 | */ |
782 | void update_wall_time(void) | 807 | static void update_wall_time(void) |
783 | { | 808 | { |
784 | struct clocksource *clock; | 809 | struct clocksource *clock; |
785 | cycle_t offset; | 810 | cycle_t offset; |
@@ -871,7 +896,7 @@ void update_wall_time(void) | |||
871 | * getboottime - Return the real time of system boot. | 896 | * getboottime - Return the real time of system boot. |
872 | * @ts: pointer to the timespec to be set | 897 | * @ts: pointer to the timespec to be set |
873 | * | 898 | * |
874 | * Returns the time of day in a timespec. | 899 | * Returns the wall-time of boot in a timespec. |
875 | * | 900 | * |
876 | * This is based on the wall_to_monotonic offset and the total suspend | 901 | * This is based on the wall_to_monotonic offset and the total suspend |
877 | * time. Calls to settimeofday will affect the value returned (which | 902 | * time. Calls to settimeofday will affect the value returned (which |
@@ -889,6 +914,55 @@ void getboottime(struct timespec *ts) | |||
889 | } | 914 | } |
890 | EXPORT_SYMBOL_GPL(getboottime); | 915 | EXPORT_SYMBOL_GPL(getboottime); |
891 | 916 | ||
917 | |||
918 | /** | ||
919 | * get_monotonic_boottime - Returns monotonic time since boot | ||
920 | * @ts: pointer to the timespec to be set | ||
921 | * | ||
922 | * Returns the monotonic time since boot in a timespec. | ||
923 | * | ||
924 | * This is similar to CLOCK_MONTONIC/ktime_get_ts, but also | ||
925 | * includes the time spent in suspend. | ||
926 | */ | ||
927 | void get_monotonic_boottime(struct timespec *ts) | ||
928 | { | ||
929 | struct timespec tomono, sleep; | ||
930 | unsigned int seq; | ||
931 | s64 nsecs; | ||
932 | |||
933 | WARN_ON(timekeeping_suspended); | ||
934 | |||
935 | do { | ||
936 | seq = read_seqbegin(&xtime_lock); | ||
937 | *ts = xtime; | ||
938 | tomono = wall_to_monotonic; | ||
939 | sleep = total_sleep_time; | ||
940 | nsecs = timekeeping_get_ns(); | ||
941 | |||
942 | } while (read_seqretry(&xtime_lock, seq)); | ||
943 | |||
944 | set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, | ||
945 | ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs); | ||
946 | } | ||
947 | EXPORT_SYMBOL_GPL(get_monotonic_boottime); | ||
948 | |||
949 | /** | ||
950 | * ktime_get_boottime - Returns monotonic time since boot in a ktime | ||
951 | * | ||
952 | * Returns the monotonic time since boot in a ktime | ||
953 | * | ||
954 | * This is similar to CLOCK_MONTONIC/ktime_get, but also | ||
955 | * includes the time spent in suspend. | ||
956 | */ | ||
957 | ktime_t ktime_get_boottime(void) | ||
958 | { | ||
959 | struct timespec ts; | ||
960 | |||
961 | get_monotonic_boottime(&ts); | ||
962 | return timespec_to_ktime(ts); | ||
963 | } | ||
964 | EXPORT_SYMBOL_GPL(ktime_get_boottime); | ||
965 | |||
892 | /** | 966 | /** |
893 | * monotonic_to_bootbased - Convert the monotonic time to boot based. | 967 | * monotonic_to_bootbased - Convert the monotonic time to boot based. |
894 | * @ts: pointer to the timespec to be converted | 968 | * @ts: pointer to the timespec to be converted |
@@ -910,11 +984,6 @@ struct timespec __current_kernel_time(void) | |||
910 | return xtime; | 984 | return xtime; |
911 | } | 985 | } |
912 | 986 | ||
913 | struct timespec __get_wall_to_monotonic(void) | ||
914 | { | ||
915 | return wall_to_monotonic; | ||
916 | } | ||
917 | |||
918 | struct timespec current_kernel_time(void) | 987 | struct timespec current_kernel_time(void) |
919 | { | 988 | { |
920 | struct timespec now; | 989 | struct timespec now; |
@@ -946,3 +1015,48 @@ struct timespec get_monotonic_coarse(void) | |||
946 | now.tv_nsec + mono.tv_nsec); | 1015 | now.tv_nsec + mono.tv_nsec); |
947 | return now; | 1016 | return now; |
948 | } | 1017 | } |
1018 | |||
1019 | /* | ||
1020 | * The 64-bit jiffies value is not atomic - you MUST NOT read it | ||
1021 | * without sampling the sequence number in xtime_lock. | ||
1022 | * jiffies is defined in the linker script... | ||
1023 | */ | ||
1024 | void do_timer(unsigned long ticks) | ||
1025 | { | ||
1026 | jiffies_64 += ticks; | ||
1027 | update_wall_time(); | ||
1028 | calc_global_load(ticks); | ||
1029 | } | ||
1030 | |||
1031 | /** | ||
1032 | * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic, | ||
1033 | * and sleep offsets. | ||
1034 | * @xtim: pointer to timespec to be set with xtime | ||
1035 | * @wtom: pointer to timespec to be set with wall_to_monotonic | ||
1036 | * @sleep: pointer to timespec to be set with time in suspend | ||
1037 | */ | ||
1038 | void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, | ||
1039 | struct timespec *wtom, struct timespec *sleep) | ||
1040 | { | ||
1041 | unsigned long seq; | ||
1042 | |||
1043 | do { | ||
1044 | seq = read_seqbegin(&xtime_lock); | ||
1045 | *xtim = xtime; | ||
1046 | *wtom = wall_to_monotonic; | ||
1047 | *sleep = total_sleep_time; | ||
1048 | } while (read_seqretry(&xtime_lock, seq)); | ||
1049 | } | ||
1050 | |||
1051 | /** | ||
1052 | * xtime_update() - advances the timekeeping infrastructure | ||
1053 | * @ticks: number of ticks, that have elapsed since the last call. | ||
1054 | * | ||
1055 | * Must be called with interrupts disabled. | ||
1056 | */ | ||
1057 | void xtime_update(unsigned long ticks) | ||
1058 | { | ||
1059 | write_seqlock(&xtime_lock); | ||
1060 | do_timer(ticks); | ||
1061 | write_sequnlock(&xtime_lock); | ||
1062 | } | ||
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c index 2f3b585b8d7d..a5d0a3a85dd8 100644 --- a/kernel/time/timer_stats.c +++ b/kernel/time/timer_stats.c | |||
@@ -236,7 +236,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | |||
236 | unsigned int timer_flag) | 236 | unsigned int timer_flag) |
237 | { | 237 | { |
238 | /* | 238 | /* |
239 | * It doesnt matter which lock we take: | 239 | * It doesn't matter which lock we take: |
240 | */ | 240 | */ |
241 | raw_spinlock_t *lock; | 241 | raw_spinlock_t *lock; |
242 | struct entry *entry, input; | 242 | struct entry *entry, input; |