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 | } | ||
