diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:28:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:59 -0500 |
commit | 54cdfdb47f73b5af3d1ebb0f1e383efbe70fde9e (patch) | |
tree | e2f76277f6b7546e53c3a1d025e31bceb10bbff5 /include | |
parent | d40891e75fc1f646dce57d5d3bd1349a6aaf7a0e (diff) |
[PATCH] hrtimers: add high resolution timer support
Implement high resolution timers on top of the hrtimers infrastructure and the
clockevents / tick-management framework. This provides accurate timers for
all hrtimer subsystem users.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/hrtimer.h | 116 | ||||
-rw-r--r-- | include/linux/interrupt.h | 3 | ||||
-rw-r--r-- | include/linux/ktime.h | 3 |
3 files changed, 114 insertions, 8 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index e95c96c971c0..4ecd991431b4 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -41,16 +41,35 @@ enum hrtimer_restart { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Bit values to track state of the timer | 44 | * hrtimer callback modes: |
45 | * | ||
46 | * HRTIMER_CB_SOFTIRQ: Callback must run in softirq context | ||
47 | * HRTIMER_CB_IRQSAFE: Callback may run in hardirq context | ||
48 | * HRTIMER_CB_IRQSAFE_NO_RESTART: Callback may run in hardirq context and | ||
49 | * does not restart the timer | ||
50 | * HRTIMER_CB_IRQSAFE_NO_SOFTIRQ: Callback must run in softirq context | ||
51 | * Special mode for tick emultation | ||
52 | */ | ||
53 | enum hrtimer_cb_mode { | ||
54 | HRTIMER_CB_SOFTIRQ, | ||
55 | HRTIMER_CB_IRQSAFE, | ||
56 | HRTIMER_CB_IRQSAFE_NO_RESTART, | ||
57 | HRTIMER_CB_IRQSAFE_NO_SOFTIRQ, | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * Values to track state of the timer | ||
45 | * | 62 | * |
46 | * Possible states: | 63 | * Possible states: |
47 | * | 64 | * |
48 | * 0x00 inactive | 65 | * 0x00 inactive |
49 | * 0x01 enqueued into rbtree | 66 | * 0x01 enqueued into rbtree |
50 | * 0x02 callback function running | 67 | * 0x02 callback function running |
68 | * 0x04 callback pending (high resolution mode) | ||
69 | * | ||
70 | * Special case: | ||
51 | * 0x03 callback function running and enqueued | 71 | * 0x03 callback function running and enqueued |
52 | * (was requeued on another CPU) | 72 | * (was requeued on another CPU) |
53 | * | ||
54 | * The "callback function running and enqueued" status is only possible on | 73 | * The "callback function running and enqueued" status is only possible on |
55 | * SMP. It happens for example when a posix timer expired and the callback | 74 | * SMP. It happens for example when a posix timer expired and the callback |
56 | * queued a signal. Between dropping the lock which protects the posix timer | 75 | * queued a signal. Between dropping the lock which protects the posix timer |
@@ -67,6 +86,7 @@ enum hrtimer_restart { | |||
67 | #define HRTIMER_STATE_INACTIVE 0x00 | 86 | #define HRTIMER_STATE_INACTIVE 0x00 |
68 | #define HRTIMER_STATE_ENQUEUED 0x01 | 87 | #define HRTIMER_STATE_ENQUEUED 0x01 |
69 | #define HRTIMER_STATE_CALLBACK 0x02 | 88 | #define HRTIMER_STATE_CALLBACK 0x02 |
89 | #define HRTIMER_STATE_PENDING 0x04 | ||
70 | 90 | ||
71 | /** | 91 | /** |
72 | * struct hrtimer - the basic hrtimer structure | 92 | * struct hrtimer - the basic hrtimer structure |
@@ -77,8 +97,17 @@ enum hrtimer_restart { | |||
77 | * @function: timer expiry callback function | 97 | * @function: timer expiry callback function |
78 | * @base: pointer to the timer base (per cpu and per clock) | 98 | * @base: pointer to the timer base (per cpu and per clock) |
79 | * @state: state information (See bit values above) | 99 | * @state: state information (See bit values above) |
100 | * @cb_mode: high resolution timer feature to select the callback execution | ||
101 | * mode | ||
102 | * @cb_entry: list head to enqueue an expired timer into the callback list | ||
103 | * @start_site: timer statistics field to store the site where the timer | ||
104 | * was started | ||
105 | * @start_comm: timer statistics field to store the name of the process which | ||
106 | * started the timer | ||
107 | * @start_pid: timer statistics field to store the pid of the task which | ||
108 | * started the timer | ||
80 | * | 109 | * |
81 | * The hrtimer structure must be initialized by init_hrtimer_#CLOCKTYPE() | 110 | * The hrtimer structure must be initialized by hrtimer_init() |
82 | */ | 111 | */ |
83 | struct hrtimer { | 112 | struct hrtimer { |
84 | struct rb_node node; | 113 | struct rb_node node; |
@@ -86,6 +115,10 @@ struct hrtimer { | |||
86 | enum hrtimer_restart (*function)(struct hrtimer *); | 115 | enum hrtimer_restart (*function)(struct hrtimer *); |
87 | struct hrtimer_clock_base *base; | 116 | struct hrtimer_clock_base *base; |
88 | unsigned long state; | 117 | unsigned long state; |
118 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
119 | enum hrtimer_cb_mode cb_mode; | ||
120 | struct list_head cb_entry; | ||
121 | #endif | ||
89 | }; | 122 | }; |
90 | 123 | ||
91 | /** | 124 | /** |
@@ -110,6 +143,9 @@ struct hrtimer_sleeper { | |||
110 | * @get_time: function to retrieve the current time of the clock | 143 | * @get_time: function to retrieve the current time of the clock |
111 | * @get_softirq_time: function to retrieve the current time from the softirq | 144 | * @get_softirq_time: function to retrieve the current time from the softirq |
112 | * @softirq_time: the time when running the hrtimer queue in the softirq | 145 | * @softirq_time: the time when running the hrtimer queue in the softirq |
146 | * @cb_pending: list of timers where the callback is pending | ||
147 | * @offset: offset of this clock to the monotonic base | ||
148 | * @reprogram: function to reprogram the timer event | ||
113 | */ | 149 | */ |
114 | struct hrtimer_clock_base { | 150 | struct hrtimer_clock_base { |
115 | struct hrtimer_cpu_base *cpu_base; | 151 | struct hrtimer_cpu_base *cpu_base; |
@@ -120,6 +156,12 @@ struct hrtimer_clock_base { | |||
120 | ktime_t (*get_time)(void); | 156 | ktime_t (*get_time)(void); |
121 | ktime_t (*get_softirq_time)(void); | 157 | ktime_t (*get_softirq_time)(void); |
122 | ktime_t softirq_time; | 158 | ktime_t softirq_time; |
159 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
160 | ktime_t offset; | ||
161 | int (*reprogram)(struct hrtimer *t, | ||
162 | struct hrtimer_clock_base *b, | ||
163 | ktime_t n); | ||
164 | #endif | ||
123 | }; | 165 | }; |
124 | 166 | ||
125 | #define HRTIMER_MAX_CLOCK_BASES 2 | 167 | #define HRTIMER_MAX_CLOCK_BASES 2 |
@@ -131,19 +173,74 @@ struct hrtimer_clock_base { | |||
131 | * @lock_key: the lock_class_key for use with lockdep | 173 | * @lock_key: the lock_class_key for use with lockdep |
132 | * @clock_base: array of clock bases for this cpu | 174 | * @clock_base: array of clock bases for this cpu |
133 | * @curr_timer: the timer which is executing a callback right now | 175 | * @curr_timer: the timer which is executing a callback right now |
176 | * @expires_next: absolute time of the next event which was scheduled | ||
177 | * via clock_set_next_event() | ||
178 | * @hres_active: State of high resolution mode | ||
179 | * @check_clocks: Indictator, when set evaluate time source and clock | ||
180 | * event devices whether high resolution mode can be | ||
181 | * activated. | ||
182 | * @cb_pending: Expired timers are moved from the rbtree to this | ||
183 | * list in the timer interrupt. The list is processed | ||
184 | * in the softirq. | ||
185 | * @nr_events: Total number of timer interrupt events | ||
134 | */ | 186 | */ |
135 | struct hrtimer_cpu_base { | 187 | struct hrtimer_cpu_base { |
136 | spinlock_t lock; | 188 | spinlock_t lock; |
137 | struct lock_class_key lock_key; | 189 | struct lock_class_key lock_key; |
138 | struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; | 190 | struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; |
191 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
192 | ktime_t expires_next; | ||
193 | int hres_active; | ||
194 | struct list_head cb_pending; | ||
195 | unsigned long nr_events; | ||
196 | #endif | ||
139 | }; | 197 | }; |
140 | 198 | ||
199 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
200 | struct clock_event_device; | ||
201 | |||
202 | extern void clock_was_set(void); | ||
203 | extern void hrtimer_interrupt(struct clock_event_device *dev); | ||
204 | |||
205 | /* | ||
206 | * In high resolution mode the time reference must be read accurate | ||
207 | */ | ||
208 | static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) | ||
209 | { | ||
210 | return timer->base->get_time(); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * The resolution of the clocks. The resolution value is returned in | ||
215 | * the clock_getres() system call to give application programmers an | ||
216 | * idea of the (in)accuracy of timers. Timer values are rounded up to | ||
217 | * this resolution values. | ||
218 | */ | ||
219 | # define KTIME_HIGH_RES (ktime_t) { .tv64 = 1 } | ||
220 | # define KTIME_MONOTONIC_RES KTIME_HIGH_RES | ||
221 | |||
222 | #else | ||
223 | |||
224 | # define KTIME_MONOTONIC_RES KTIME_LOW_RES | ||
225 | |||
141 | /* | 226 | /* |
142 | * clock_was_set() is a NOP for non- high-resolution systems. The | 227 | * clock_was_set() is a NOP for non- high-resolution systems. The |
143 | * time-sorted order guarantees that a timer does not expire early and | 228 | * time-sorted order guarantees that a timer does not expire early and |
144 | * is expired in the next softirq when the clock was advanced. | 229 | * is expired in the next softirq when the clock was advanced. |
145 | */ | 230 | */ |
146 | #define clock_was_set() do { } while (0) | 231 | static inline void clock_was_set(void) { } |
232 | |||
233 | /* | ||
234 | * In non high resolution mode the time reference is taken from | ||
235 | * the base softirq time variable. | ||
236 | */ | ||
237 | static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) | ||
238 | { | ||
239 | return timer->base->softirq_time; | ||
240 | } | ||
241 | |||
242 | #endif | ||
243 | |||
147 | extern ktime_t ktime_get(void); | 244 | extern ktime_t ktime_get(void); |
148 | extern ktime_t ktime_get_real(void); | 245 | extern ktime_t ktime_get_real(void); |
149 | 246 | ||
@@ -168,9 +265,7 @@ static inline int hrtimer_restart(struct hrtimer *timer) | |||
168 | extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); | 265 | extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); |
169 | extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); | 266 | extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); |
170 | 267 | ||
171 | #ifdef CONFIG_NO_IDLE_HZ | ||
172 | extern ktime_t hrtimer_get_next_event(void); | 268 | extern ktime_t hrtimer_get_next_event(void); |
173 | #endif | ||
174 | 269 | ||
175 | /* | 270 | /* |
176 | * A timer is active, when it is enqueued into the rbtree or the callback | 271 | * A timer is active, when it is enqueued into the rbtree or the callback |
@@ -181,6 +276,15 @@ static inline int hrtimer_active(const struct hrtimer *timer) | |||
181 | return timer->state != HRTIMER_STATE_INACTIVE; | 276 | return timer->state != HRTIMER_STATE_INACTIVE; |
182 | } | 277 | } |
183 | 278 | ||
279 | /* | ||
280 | * Helper function to check, whether the timer is on one of the queues | ||
281 | */ | ||
282 | static inline int hrtimer_is_queued(struct hrtimer *timer) | ||
283 | { | ||
284 | return timer->state & | ||
285 | (HRTIMER_STATE_ENQUEUED | HRTIMER_STATE_PENDING); | ||
286 | } | ||
287 | |||
184 | /* Forward a hrtimer so it expires after now: */ | 288 | /* Forward a hrtimer so it expires after now: */ |
185 | extern unsigned long | 289 | extern unsigned long |
186 | hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); | 290 | hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 690113d07698..e5ea1411050b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -242,6 +242,9 @@ enum | |||
242 | BLOCK_SOFTIRQ, | 242 | BLOCK_SOFTIRQ, |
243 | TASKLET_SOFTIRQ, | 243 | TASKLET_SOFTIRQ, |
244 | SCHED_SOFTIRQ, | 244 | SCHED_SOFTIRQ, |
245 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
246 | HRTIMER_SOFTIRQ, | ||
247 | #endif | ||
245 | }; | 248 | }; |
246 | 249 | ||
247 | /* softirq mask and active fields moved to irq_cpustat_t in | 250 | /* softirq mask and active fields moved to irq_cpustat_t in |
diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 7444a6326231..c68c7ac6b232 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h | |||
@@ -261,8 +261,7 @@ static inline s64 ktime_to_ns(const ktime_t kt) | |||
261 | * idea of the (in)accuracy of timers. Timer values are rounded up to | 261 | * idea of the (in)accuracy of timers. Timer values are rounded up to |
262 | * this resolution values. | 262 | * this resolution values. |
263 | */ | 263 | */ |
264 | #define KTIME_REALTIME_RES (ktime_t){ .tv64 = TICK_NSEC } | 264 | #define KTIME_LOW_RES (ktime_t){ .tv64 = TICK_NSEC } |
265 | #define KTIME_MONOTONIC_RES (ktime_t){ .tv64 = TICK_NSEC } | ||
266 | 265 | ||
267 | /* Get the monotonic time in timespec format: */ | 266 | /* Get the monotonic time in timespec format: */ |
268 | extern void ktime_get_ts(struct timespec *ts); | 267 | extern void ktime_get_ts(struct timespec *ts); |