diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 21:53:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 21:53:35 -0400 |
commit | 420c1c572d4ceaa2f37b6311b7017ac6cf049fe2 (patch) | |
tree | df04e6b4b756b7a46d9887462d54a3ad0e1f91d5 /kernel/time | |
parent | 9620639b7ea3843983f4ced8b4c81eb4d8974838 (diff) | |
parent | 6e6823d17b157f185be09f4c70181299f9273f0b (diff) |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (62 commits)
posix-clocks: Check write permissions in posix syscalls
hrtimer: Remove empty hrtimer_init_hres_timer()
hrtimer: Update hrtimer->state documentation
hrtimer: Update base[CLOCK_BOOTTIME].offset correctly
timers: Export CLOCK_BOOTTIME via the posix timers interface
timers: Add CLOCK_BOOTTIME hrtimer base
time: Extend get_xtime_and_monotonic_offset() to also return sleep
time: Introduce get_monotonic_boottime and ktime_get_boottime
hrtimers: extend hrtimer base code to handle more then 2 clockids
ntp: Remove redundant and incorrect parameter check
mn10300: Switch do_timer() to xtimer_update()
posix clocks: Introduce dynamic clocks
posix-timers: Cleanup namespace
posix-timers: Add support for fd based clocks
x86: Add clock_adjtime for x86
posix-timers: Introduce a syscall for clock tuning.
time: Splitout compat timex accessors
ntp: Add ADJ_SETOFFSET mode bit
time: Introduce timekeeping_inject_offset
posix-timer: Update comment
...
Fix up new system-call-related conflicts in
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/syscall_table_32.S
(name_to_handle_at()/open_by_handle_at() vs clock_adjtime()), and some
due to movement of get_jiffies_64() in:
kernel/time.c
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 | 20 | ||||
-rw-r--r-- | kernel/time/ntp.c | 13 | ||||
-rw-r--r-- | kernel/time/posix-clock.c | 451 | ||||
-rw-r--r-- | kernel/time/tick-broadcast.c | 1 | ||||
-rw-r--r-- | kernel/time/tick-common.c | 1 | ||||
-rw-r--r-- | kernel/time/tick-internal.h | 9 | ||||
-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 | 141 |
11 files changed, 628 insertions, 14 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..b2fa506667c0 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 |
@@ -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..5f1bb8e2008f 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,17 @@ 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 (!(txc->modes & ADJ_NANO)) | ||
656 | delta.tv_nsec *= 1000; | ||
657 | result = timekeeping_inject_offset(&delta); | ||
658 | if (result) | ||
659 | return result; | ||
660 | } | ||
661 | |||
649 | getnstimeofday(&ts); | 662 | getnstimeofday(&ts); |
650 | 663 | ||
651 | write_seqlock_irq(&xtime_lock); | 664 | 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..25028dd4fa18 --- /dev/null +++ b/kernel/time/posix-clock.c | |||
@@ -0,0 +1,451 @@ | |||
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/mutex.h> | ||
23 | #include <linux/posix-clock.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/syscalls.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | |||
28 | static void delete_clock(struct kref *kref); | ||
29 | |||
30 | /* | ||
31 | * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. | ||
32 | */ | ||
33 | static struct posix_clock *get_posix_clock(struct file *fp) | ||
34 | { | ||
35 | struct posix_clock *clk = fp->private_data; | ||
36 | |||
37 | mutex_lock(&clk->mutex); | ||
38 | |||
39 | if (!clk->zombie) | ||
40 | return clk; | ||
41 | |||
42 | mutex_unlock(&clk->mutex); | ||
43 | |||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static void put_posix_clock(struct posix_clock *clk) | ||
48 | { | ||
49 | mutex_unlock(&clk->mutex); | ||
50 | } | ||
51 | |||
52 | static ssize_t posix_clock_read(struct file *fp, char __user *buf, | ||
53 | size_t count, loff_t *ppos) | ||
54 | { | ||
55 | struct posix_clock *clk = get_posix_clock(fp); | ||
56 | int err = -EINVAL; | ||
57 | |||
58 | if (!clk) | ||
59 | return -ENODEV; | ||
60 | |||
61 | if (clk->ops.read) | ||
62 | err = clk->ops.read(clk, fp->f_flags, buf, count); | ||
63 | |||
64 | put_posix_clock(clk); | ||
65 | |||
66 | return err; | ||
67 | } | ||
68 | |||
69 | static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) | ||
70 | { | ||
71 | struct posix_clock *clk = get_posix_clock(fp); | ||
72 | int result = 0; | ||
73 | |||
74 | if (!clk) | ||
75 | return -ENODEV; | ||
76 | |||
77 | if (clk->ops.poll) | ||
78 | result = clk->ops.poll(clk, fp, wait); | ||
79 | |||
80 | put_posix_clock(clk); | ||
81 | |||
82 | return result; | ||
83 | } | ||
84 | |||
85 | static int posix_clock_fasync(int fd, struct file *fp, int on) | ||
86 | { | ||
87 | struct posix_clock *clk = get_posix_clock(fp); | ||
88 | int err = 0; | ||
89 | |||
90 | if (!clk) | ||
91 | return -ENODEV; | ||
92 | |||
93 | if (clk->ops.fasync) | ||
94 | err = clk->ops.fasync(clk, fd, fp, on); | ||
95 | |||
96 | put_posix_clock(clk); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) | ||
102 | { | ||
103 | struct posix_clock *clk = get_posix_clock(fp); | ||
104 | int err = -ENODEV; | ||
105 | |||
106 | if (!clk) | ||
107 | return -ENODEV; | ||
108 | |||
109 | if (clk->ops.mmap) | ||
110 | err = clk->ops.mmap(clk, vma); | ||
111 | |||
112 | put_posix_clock(clk); | ||
113 | |||
114 | return err; | ||
115 | } | ||
116 | |||
117 | static long posix_clock_ioctl(struct file *fp, | ||
118 | unsigned int cmd, unsigned long arg) | ||
119 | { | ||
120 | struct posix_clock *clk = get_posix_clock(fp); | ||
121 | int err = -ENOTTY; | ||
122 | |||
123 | if (!clk) | ||
124 | return -ENODEV; | ||
125 | |||
126 | if (clk->ops.ioctl) | ||
127 | err = clk->ops.ioctl(clk, cmd, arg); | ||
128 | |||
129 | put_posix_clock(clk); | ||
130 | |||
131 | return err; | ||
132 | } | ||
133 | |||
134 | #ifdef CONFIG_COMPAT | ||
135 | static long posix_clock_compat_ioctl(struct file *fp, | ||
136 | unsigned int cmd, unsigned long arg) | ||
137 | { | ||
138 | struct posix_clock *clk = get_posix_clock(fp); | ||
139 | int err = -ENOTTY; | ||
140 | |||
141 | if (!clk) | ||
142 | return -ENODEV; | ||
143 | |||
144 | if (clk->ops.ioctl) | ||
145 | err = clk->ops.ioctl(clk, cmd, arg); | ||
146 | |||
147 | put_posix_clock(clk); | ||
148 | |||
149 | return err; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | static int posix_clock_open(struct inode *inode, struct file *fp) | ||
154 | { | ||
155 | int err; | ||
156 | struct posix_clock *clk = | ||
157 | container_of(inode->i_cdev, struct posix_clock, cdev); | ||
158 | |||
159 | mutex_lock(&clk->mutex); | ||
160 | |||
161 | if (clk->zombie) { | ||
162 | err = -ENODEV; | ||
163 | goto out; | ||
164 | } | ||
165 | if (clk->ops.open) | ||
166 | err = clk->ops.open(clk, fp->f_mode); | ||
167 | else | ||
168 | err = 0; | ||
169 | |||
170 | if (!err) { | ||
171 | kref_get(&clk->kref); | ||
172 | fp->private_data = clk; | ||
173 | } | ||
174 | out: | ||
175 | mutex_unlock(&clk->mutex); | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | static int posix_clock_release(struct inode *inode, struct file *fp) | ||
180 | { | ||
181 | struct posix_clock *clk = fp->private_data; | ||
182 | int err = 0; | ||
183 | |||
184 | if (clk->ops.release) | ||
185 | err = clk->ops.release(clk); | ||
186 | |||
187 | kref_put(&clk->kref, delete_clock); | ||
188 | |||
189 | fp->private_data = NULL; | ||
190 | |||
191 | return err; | ||
192 | } | ||
193 | |||
194 | static const struct file_operations posix_clock_file_operations = { | ||
195 | .owner = THIS_MODULE, | ||
196 | .llseek = no_llseek, | ||
197 | .read = posix_clock_read, | ||
198 | .poll = posix_clock_poll, | ||
199 | .unlocked_ioctl = posix_clock_ioctl, | ||
200 | .open = posix_clock_open, | ||
201 | .release = posix_clock_release, | ||
202 | .fasync = posix_clock_fasync, | ||
203 | .mmap = posix_clock_mmap, | ||
204 | #ifdef CONFIG_COMPAT | ||
205 | .compat_ioctl = posix_clock_compat_ioctl, | ||
206 | #endif | ||
207 | }; | ||
208 | |||
209 | int posix_clock_register(struct posix_clock *clk, dev_t devid) | ||
210 | { | ||
211 | int err; | ||
212 | |||
213 | kref_init(&clk->kref); | ||
214 | mutex_init(&clk->mutex); | ||
215 | |||
216 | cdev_init(&clk->cdev, &posix_clock_file_operations); | ||
217 | clk->cdev.owner = clk->ops.owner; | ||
218 | err = cdev_add(&clk->cdev, devid, 1); | ||
219 | if (err) | ||
220 | goto no_cdev; | ||
221 | |||
222 | return err; | ||
223 | no_cdev: | ||
224 | mutex_destroy(&clk->mutex); | ||
225 | return err; | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(posix_clock_register); | ||
228 | |||
229 | static void delete_clock(struct kref *kref) | ||
230 | { | ||
231 | struct posix_clock *clk = container_of(kref, struct posix_clock, kref); | ||
232 | mutex_destroy(&clk->mutex); | ||
233 | if (clk->release) | ||
234 | clk->release(clk); | ||
235 | } | ||
236 | |||
237 | void posix_clock_unregister(struct posix_clock *clk) | ||
238 | { | ||
239 | cdev_del(&clk->cdev); | ||
240 | |||
241 | mutex_lock(&clk->mutex); | ||
242 | clk->zombie = true; | ||
243 | mutex_unlock(&clk->mutex); | ||
244 | |||
245 | kref_put(&clk->kref, delete_clock); | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(posix_clock_unregister); | ||
248 | |||
249 | struct posix_clock_desc { | ||
250 | struct file *fp; | ||
251 | struct posix_clock *clk; | ||
252 | }; | ||
253 | |||
254 | static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd) | ||
255 | { | ||
256 | struct file *fp = fget(CLOCKID_TO_FD(id)); | ||
257 | int err = -EINVAL; | ||
258 | |||
259 | if (!fp) | ||
260 | return err; | ||
261 | |||
262 | if (fp->f_op->open != posix_clock_open || !fp->private_data) | ||
263 | goto out; | ||
264 | |||
265 | cd->fp = fp; | ||
266 | cd->clk = get_posix_clock(fp); | ||
267 | |||
268 | err = cd->clk ? 0 : -ENODEV; | ||
269 | out: | ||
270 | if (err) | ||
271 | fput(fp); | ||
272 | return err; | ||
273 | } | ||
274 | |||
275 | static void put_clock_desc(struct posix_clock_desc *cd) | ||
276 | { | ||
277 | put_posix_clock(cd->clk); | ||
278 | fput(cd->fp); | ||
279 | } | ||
280 | |||
281 | static int pc_clock_adjtime(clockid_t id, struct timex *tx) | ||
282 | { | ||
283 | struct posix_clock_desc cd; | ||
284 | int err; | ||
285 | |||
286 | err = get_clock_desc(id, &cd); | ||
287 | if (err) | ||
288 | return err; | ||
289 | |||
290 | if ((cd.fp->f_mode & FMODE_WRITE) == 0) { | ||
291 | err = -EACCES; | ||
292 | goto out; | ||
293 | } | ||
294 | |||
295 | if (cd.clk->ops.clock_adjtime) | ||
296 | err = cd.clk->ops.clock_adjtime(cd.clk, tx); | ||
297 | else | ||
298 | err = -EOPNOTSUPP; | ||
299 | out: | ||
300 | put_clock_desc(&cd); | ||
301 | |||
302 | return err; | ||
303 | } | ||
304 | |||
305 | static int pc_clock_gettime(clockid_t id, struct timespec *ts) | ||
306 | { | ||
307 | struct posix_clock_desc cd; | ||
308 | int err; | ||
309 | |||
310 | err = get_clock_desc(id, &cd); | ||
311 | if (err) | ||
312 | return err; | ||
313 | |||
314 | if (cd.clk->ops.clock_gettime) | ||
315 | err = cd.clk->ops.clock_gettime(cd.clk, ts); | ||
316 | else | ||
317 | err = -EOPNOTSUPP; | ||
318 | |||
319 | put_clock_desc(&cd); | ||
320 | |||
321 | return err; | ||
322 | } | ||
323 | |||
324 | static int pc_clock_getres(clockid_t id, struct timespec *ts) | ||
325 | { | ||
326 | struct posix_clock_desc cd; | ||
327 | int err; | ||
328 | |||
329 | err = get_clock_desc(id, &cd); | ||
330 | if (err) | ||
331 | return err; | ||
332 | |||
333 | if (cd.clk->ops.clock_getres) | ||
334 | err = cd.clk->ops.clock_getres(cd.clk, ts); | ||
335 | else | ||
336 | err = -EOPNOTSUPP; | ||
337 | |||
338 | put_clock_desc(&cd); | ||
339 | |||
340 | return err; | ||
341 | } | ||
342 | |||
343 | static int pc_clock_settime(clockid_t id, const struct timespec *ts) | ||
344 | { | ||
345 | struct posix_clock_desc cd; | ||
346 | int err; | ||
347 | |||
348 | err = get_clock_desc(id, &cd); | ||
349 | if (err) | ||
350 | return err; | ||
351 | |||
352 | if ((cd.fp->f_mode & FMODE_WRITE) == 0) { | ||
353 | err = -EACCES; | ||
354 | goto out; | ||
355 | } | ||
356 | |||
357 | if (cd.clk->ops.clock_settime) | ||
358 | err = cd.clk->ops.clock_settime(cd.clk, ts); | ||
359 | else | ||
360 | err = -EOPNOTSUPP; | ||
361 | out: | ||
362 | put_clock_desc(&cd); | ||
363 | |||
364 | return err; | ||
365 | } | ||
366 | |||
367 | static int pc_timer_create(struct k_itimer *kit) | ||
368 | { | ||
369 | clockid_t id = kit->it_clock; | ||
370 | struct posix_clock_desc cd; | ||
371 | int err; | ||
372 | |||
373 | err = get_clock_desc(id, &cd); | ||
374 | if (err) | ||
375 | return err; | ||
376 | |||
377 | if (cd.clk->ops.timer_create) | ||
378 | err = cd.clk->ops.timer_create(cd.clk, kit); | ||
379 | else | ||
380 | err = -EOPNOTSUPP; | ||
381 | |||
382 | put_clock_desc(&cd); | ||
383 | |||
384 | return err; | ||
385 | } | ||
386 | |||
387 | static int pc_timer_delete(struct k_itimer *kit) | ||
388 | { | ||
389 | clockid_t id = kit->it_clock; | ||
390 | struct posix_clock_desc cd; | ||
391 | int err; | ||
392 | |||
393 | err = get_clock_desc(id, &cd); | ||
394 | if (err) | ||
395 | return err; | ||
396 | |||
397 | if (cd.clk->ops.timer_delete) | ||
398 | err = cd.clk->ops.timer_delete(cd.clk, kit); | ||
399 | else | ||
400 | err = -EOPNOTSUPP; | ||
401 | |||
402 | put_clock_desc(&cd); | ||
403 | |||
404 | return err; | ||
405 | } | ||
406 | |||
407 | static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) | ||
408 | { | ||
409 | clockid_t id = kit->it_clock; | ||
410 | struct posix_clock_desc cd; | ||
411 | |||
412 | if (get_clock_desc(id, &cd)) | ||
413 | return; | ||
414 | |||
415 | if (cd.clk->ops.timer_gettime) | ||
416 | cd.clk->ops.timer_gettime(cd.clk, kit, ts); | ||
417 | |||
418 | put_clock_desc(&cd); | ||
419 | } | ||
420 | |||
421 | static int pc_timer_settime(struct k_itimer *kit, int flags, | ||
422 | struct itimerspec *ts, struct itimerspec *old) | ||
423 | { | ||
424 | clockid_t id = kit->it_clock; | ||
425 | struct posix_clock_desc cd; | ||
426 | int err; | ||
427 | |||
428 | err = get_clock_desc(id, &cd); | ||
429 | if (err) | ||
430 | return err; | ||
431 | |||
432 | if (cd.clk->ops.timer_settime) | ||
433 | err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); | ||
434 | else | ||
435 | err = -EOPNOTSUPP; | ||
436 | |||
437 | put_clock_desc(&cd); | ||
438 | |||
439 | return err; | ||
440 | } | ||
441 | |||
442 | struct k_clock clock_posix_dynamic = { | ||
443 | .clock_getres = pc_clock_getres, | ||
444 | .clock_set = pc_clock_settime, | ||
445 | .clock_get = pc_clock_gettime, | ||
446 | .clock_adj = pc_clock_adjtime, | ||
447 | .timer_create = pc_timer_create, | ||
448 | .timer_set = pc_timer_settime, | ||
449 | .timer_del = pc_timer_delete, | ||
450 | .timer_get = pc_timer_gettime, | ||
451 | }; | ||
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index a3b5aff62606..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 | ||
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index ed228ef6f6b8..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 | ||
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index f65d3a723a64..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 |
@@ -135,3 +139,8 @@ static inline int tick_device_is_functional(struct clock_event_device *dev) | |||
135 | { | 139 | { |
136 | return !(dev->features & CLOCK_EVT_FEAT_DUMMY); | 140 | return !(dev->features & CLOCK_EVT_FEAT_DUMMY); |
137 | } | 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..3bd7e3d5c632 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -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 | * |
@@ -779,7 +815,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) | |||
779 | * | 815 | * |
780 | * Called from the timer interrupt, must hold a write on xtime_lock. | 816 | * Called from the timer interrupt, must hold a write on xtime_lock. |
781 | */ | 817 | */ |
782 | void update_wall_time(void) | 818 | static void update_wall_time(void) |
783 | { | 819 | { |
784 | struct clocksource *clock; | 820 | struct clocksource *clock; |
785 | cycle_t offset; | 821 | cycle_t offset; |
@@ -871,7 +907,7 @@ void update_wall_time(void) | |||
871 | * getboottime - Return the real time of system boot. | 907 | * getboottime - Return the real time of system boot. |
872 | * @ts: pointer to the timespec to be set | 908 | * @ts: pointer to the timespec to be set |
873 | * | 909 | * |
874 | * Returns the time of day in a timespec. | 910 | * Returns the wall-time of boot in a timespec. |
875 | * | 911 | * |
876 | * This is based on the wall_to_monotonic offset and the total suspend | 912 | * This is based on the wall_to_monotonic offset and the total suspend |
877 | * time. Calls to settimeofday will affect the value returned (which | 913 | * time. Calls to settimeofday will affect the value returned (which |
@@ -889,6 +925,55 @@ void getboottime(struct timespec *ts) | |||
889 | } | 925 | } |
890 | EXPORT_SYMBOL_GPL(getboottime); | 926 | EXPORT_SYMBOL_GPL(getboottime); |
891 | 927 | ||
928 | |||
929 | /** | ||
930 | * get_monotonic_boottime - Returns monotonic time since boot | ||
931 | * @ts: pointer to the timespec to be set | ||
932 | * | ||
933 | * Returns the monotonic time since boot in a timespec. | ||
934 | * | ||
935 | * This is similar to CLOCK_MONTONIC/ktime_get_ts, but also | ||
936 | * includes the time spent in suspend. | ||
937 | */ | ||
938 | void get_monotonic_boottime(struct timespec *ts) | ||
939 | { | ||
940 | struct timespec tomono, sleep; | ||
941 | unsigned int seq; | ||
942 | s64 nsecs; | ||
943 | |||
944 | WARN_ON(timekeeping_suspended); | ||
945 | |||
946 | do { | ||
947 | seq = read_seqbegin(&xtime_lock); | ||
948 | *ts = xtime; | ||
949 | tomono = wall_to_monotonic; | ||
950 | sleep = total_sleep_time; | ||
951 | nsecs = timekeeping_get_ns(); | ||
952 | |||
953 | } while (read_seqretry(&xtime_lock, seq)); | ||
954 | |||
955 | set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, | ||
956 | ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs); | ||
957 | } | ||
958 | EXPORT_SYMBOL_GPL(get_monotonic_boottime); | ||
959 | |||
960 | /** | ||
961 | * ktime_get_boottime - Returns monotonic time since boot in a ktime | ||
962 | * | ||
963 | * Returns the monotonic time since boot in a ktime | ||
964 | * | ||
965 | * This is similar to CLOCK_MONTONIC/ktime_get, but also | ||
966 | * includes the time spent in suspend. | ||
967 | */ | ||
968 | ktime_t ktime_get_boottime(void) | ||
969 | { | ||
970 | struct timespec ts; | ||
971 | |||
972 | get_monotonic_boottime(&ts); | ||
973 | return timespec_to_ktime(ts); | ||
974 | } | ||
975 | EXPORT_SYMBOL_GPL(ktime_get_boottime); | ||
976 | |||
892 | /** | 977 | /** |
893 | * monotonic_to_bootbased - Convert the monotonic time to boot based. | 978 | * monotonic_to_bootbased - Convert the monotonic time to boot based. |
894 | * @ts: pointer to the timespec to be converted | 979 | * @ts: pointer to the timespec to be converted |
@@ -910,11 +995,6 @@ struct timespec __current_kernel_time(void) | |||
910 | return xtime; | 995 | return xtime; |
911 | } | 996 | } |
912 | 997 | ||
913 | struct timespec __get_wall_to_monotonic(void) | ||
914 | { | ||
915 | return wall_to_monotonic; | ||
916 | } | ||
917 | |||
918 | struct timespec current_kernel_time(void) | 998 | struct timespec current_kernel_time(void) |
919 | { | 999 | { |
920 | struct timespec now; | 1000 | struct timespec now; |
@@ -946,3 +1026,48 @@ struct timespec get_monotonic_coarse(void) | |||
946 | now.tv_nsec + mono.tv_nsec); | 1026 | now.tv_nsec + mono.tv_nsec); |
947 | return now; | 1027 | return now; |
948 | } | 1028 | } |
1029 | |||
1030 | /* | ||
1031 | * The 64-bit jiffies value is not atomic - you MUST NOT read it | ||
1032 | * without sampling the sequence number in xtime_lock. | ||
1033 | * jiffies is defined in the linker script... | ||
1034 | */ | ||
1035 | void do_timer(unsigned long ticks) | ||
1036 | { | ||
1037 | jiffies_64 += ticks; | ||
1038 | update_wall_time(); | ||
1039 | calc_global_load(ticks); | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic, | ||
1044 | * and sleep offsets. | ||
1045 | * @xtim: pointer to timespec to be set with xtime | ||
1046 | * @wtom: pointer to timespec to be set with wall_to_monotonic | ||
1047 | * @sleep: pointer to timespec to be set with time in suspend | ||
1048 | */ | ||
1049 | void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, | ||
1050 | struct timespec *wtom, struct timespec *sleep) | ||
1051 | { | ||
1052 | unsigned long seq; | ||
1053 | |||
1054 | do { | ||
1055 | seq = read_seqbegin(&xtime_lock); | ||
1056 | *xtim = xtime; | ||
1057 | *wtom = wall_to_monotonic; | ||
1058 | *sleep = total_sleep_time; | ||
1059 | } while (read_seqretry(&xtime_lock, seq)); | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * xtime_update() - advances the timekeeping infrastructure | ||
1064 | * @ticks: number of ticks, that have elapsed since the last call. | ||
1065 | * | ||
1066 | * Must be called with interrupts disabled. | ||
1067 | */ | ||
1068 | void xtime_update(unsigned long ticks) | ||
1069 | { | ||
1070 | write_seqlock(&xtime_lock); | ||
1071 | do_timer(ticks); | ||
1072 | write_sequnlock(&xtime_lock); | ||
1073 | } | ||