Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6-block.git] / kernel / time / tick-oneshot.c
CommitLineData
79bf2bb3
TG
1/*
2 * linux/kernel/time/tick-oneshot.c
3 *
4 * This file contains functions which manage high resolution tick
5 * related events.
6 *
7 * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de>
8 * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar
9 * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner
10 *
11 * This code is licenced under the GPL version 2. For details see
12 * kernel-base/COPYING.
13 */
14#include <linux/cpu.h>
15#include <linux/err.h>
16#include <linux/hrtimer.h>
d7b90689 17#include <linux/interrupt.h>
79bf2bb3
TG
18#include <linux/percpu.h>
19#include <linux/profile.h>
20#include <linux/sched.h>
79bf2bb3
TG
21
22#include "tick-internal.h"
23
7205656a
TG
24/**
25 * tick_program_event
26 */
27int tick_program_event(ktime_t expires, int force)
28{
909ea964 29 struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
7205656a 30
2456e855 31 if (unlikely(expires == KTIME_MAX)) {
d2540875
VK
32 /*
33 * We don't need the clock event device any more, stop it.
34 */
d7eb231c 35 clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT_STOPPED);
39c82caf 36 dev->next_event = KTIME_MAX;
d2540875
VK
37 return 0;
38 }
39
472c4a94 40 if (unlikely(clockevent_state_oneshot_stopped(dev))) {
d2540875
VK
41 /*
42 * We need the clock event again, configure it in ONESHOT mode
43 * before using it.
44 */
d7eb231c 45 clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
d2540875
VK
46 }
47
d1748302 48 return clockevents_program_event(dev, expires, force);
7205656a
TG
49}
50
cd05a1f8
TG
51/**
52 * tick_resume_onshot - resume oneshot mode
53 */
54void tick_resume_oneshot(void)
55{
d1748302 56 struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
cd05a1f8 57
d7eb231c 58 clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
d1748302 59 clockevents_program_event(dev, ktime_get(), true);
cd05a1f8
TG
60}
61
79bf2bb3
TG
62/**
63 * tick_setup_oneshot - setup the event device for oneshot mode (hres or nohz)
64 */
65void tick_setup_oneshot(struct clock_event_device *newdev,
66 void (*handler)(struct clock_event_device *),
67 ktime_t next_event)
68{
69 newdev->event_handler = handler;
d7eb231c 70 clockevents_switch_state(newdev, CLOCK_EVT_STATE_ONESHOT);
d1748302 71 clockevents_program_event(newdev, next_event, true);
79bf2bb3
TG
72}
73
74/**
75 * tick_switch_to_oneshot - switch to oneshot mode
76 */
77int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
78{
22127e93 79 struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
79bf2bb3
TG
80 struct clock_event_device *dev = td->evtdev;
81
82 if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
820de5c3
IM
83 !tick_device_is_functional(dev)) {
84
85 printk(KERN_INFO "Clockevents: "
86 "could not switch to one-shot mode:");
87 if (!dev) {
88 printk(" no tick device\n");
89 } else {
90 if (!tick_device_is_functional(dev))
91 printk(" %s is not functional.\n", dev->name);
92 else
93 printk(" %s does not support one-shot mode.\n",
94 dev->name);
95 }
79bf2bb3 96 return -EINVAL;
820de5c3 97 }
79bf2bb3
TG
98
99 td->mode = TICKDEV_MODE_ONESHOT;
100 dev->event_handler = handler;
d7eb231c 101 clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
79bf2bb3
TG
102 tick_broadcast_switch_to_oneshot();
103 return 0;
104}
105
cd6d95d8
TG
106/**
107 * tick_check_oneshot_mode - check whether the system is in oneshot mode
108 *
109 * returns 1 when either nohz or highres are enabled. otherwise 0.
110 */
111int tick_oneshot_mode_active(void)
112{
113 unsigned long flags;
114 int ret;
115
116 local_irq_save(flags);
909ea964 117 ret = __this_cpu_read(tick_cpu_device.mode) == TICKDEV_MODE_ONESHOT;
cd6d95d8
TG
118 local_irq_restore(flags);
119
120 return ret;
121}
122
79bf2bb3
TG
123#ifdef CONFIG_HIGH_RES_TIMERS
124/**
125 * tick_init_highres - switch to high resolution mode
126 *
127 * Called with interrupts disabled.
128 */
129int tick_init_highres(void)
130{
131 return tick_switch_to_oneshot(hrtimer_interrupt);
132}
133#endif