blob: 30514625eee0416ae429a5c7131cd90706b2b836 [file] [log] [blame]
Jesper Nilssonec87ee22007-11-30 17:46:11 +01001/*
Mikael Starvik51533b62005-07-27 11:44:44 -07002 * linux/arch/cris/kernel/fasttimer.c
3 *
4 * Fast timers for ETRAX FS
Mikael Starvik51533b62005-07-27 11:44:44 -07005 *
Jesper Nilssonec87ee22007-11-30 17:46:11 +01006 * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden
Mikael Starvik51533b62005-07-27 11:44:44 -07007 */
8
9#include <linux/errno.h>
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/string.h>
14#include <linux/vmalloc.h>
15#include <linux/interrupt.h>
16#include <linux/time.h>
17#include <linux/delay.h>
18
19#include <asm/irq.h>
20#include <asm/system.h>
21
Mikael Starvik51533b62005-07-27 11:44:44 -070022#include <linux/version.h>
23
Jesper Nilssonec87ee22007-11-30 17:46:11 +010024#include <hwregs/reg_map.h>
25#include <hwregs/reg_rdwr.h>
26#include <hwregs/timer_defs.h>
Mikael Starvik51533b62005-07-27 11:44:44 -070027#include <asm/fasttimer.h>
28#include <linux/proc_fs.h>
29
30/*
31 * timer0 is running at 100MHz and generating jiffies timer ticks
32 * at 100 or 1000 HZ.
33 * fasttimer gives an API that gives timers that expire "between" the jiffies
34 * giving microsecond resolution (10 ns).
35 * fasttimer uses reg_timer_rw_trig register to get interrupt when
36 * r_time reaches a certain value.
37 */
38
39
40#define DEBUG_LOG_INCLUDED
41#define FAST_TIMER_LOG
Jesper Nilssonec87ee22007-11-30 17:46:11 +010042/* #define FAST_TIMER_TEST */
Mikael Starvik51533b62005-07-27 11:44:44 -070043
44#define FAST_TIMER_SANITY_CHECKS
45
46#ifdef FAST_TIMER_SANITY_CHECKS
47#define SANITYCHECK(x) x
48static int sanity_failed = 0;
49#else
50#define SANITYCHECK(x)
51#endif
52
53#define D1(x)
54#define D2(x)
55#define DP(x)
56
Jesper Nilssonec87ee22007-11-30 17:46:11 +010057static unsigned int fast_timer_running;
58static unsigned int fast_timers_added;
59static unsigned int fast_timers_started;
60static unsigned int fast_timers_expired;
61static unsigned int fast_timers_deleted;
62static unsigned int fast_timer_is_init;
63static unsigned int fast_timer_ints;
Mikael Starvik51533b62005-07-27 11:44:44 -070064
65struct fast_timer *fast_timer_list = NULL;
66
67#ifdef DEBUG_LOG_INCLUDED
68#define DEBUG_LOG_MAX 128
69static const char * debug_log_string[DEBUG_LOG_MAX];
70static unsigned long debug_log_value[DEBUG_LOG_MAX];
Jesper Nilssonec87ee22007-11-30 17:46:11 +010071static unsigned int debug_log_cnt;
72static unsigned int debug_log_cnt_wrapped;
Mikael Starvik51533b62005-07-27 11:44:44 -070073
74#define DEBUG_LOG(string, value) \
75{ \
76 unsigned long log_flags; \
77 local_irq_save(log_flags); \
78 debug_log_string[debug_log_cnt] = (string); \
79 debug_log_value[debug_log_cnt] = (unsigned long)(value); \
80 if (++debug_log_cnt >= DEBUG_LOG_MAX) \
81 { \
82 debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
83 debug_log_cnt_wrapped = 1; \
84 } \
85 local_irq_restore(log_flags); \
86}
87#else
88#define DEBUG_LOG(string, value)
89#endif
90
91
92#define NUM_TIMER_STATS 16
93#ifdef FAST_TIMER_LOG
94struct fast_timer timer_added_log[NUM_TIMER_STATS];
95struct fast_timer timer_started_log[NUM_TIMER_STATS];
96struct fast_timer timer_expired_log[NUM_TIMER_STATS];
97#endif
98
99int timer_div_settings[NUM_TIMER_STATS];
100int timer_delay_settings[NUM_TIMER_STATS];
101
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100102struct work_struct fast_work;
Mikael Starvik51533b62005-07-27 11:44:44 -0700103
104static void
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100105timer_trig_handler(struct work_struct *work);
Mikael Starvik51533b62005-07-27 11:44:44 -0700106
107
108
109/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100110inline void do_gettimeofday_fast(struct fasttime_t *tv)
Mikael Starvik51533b62005-07-27 11:44:44 -0700111{
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100112 tv->tv_jiff = jiffies;
113 tv->tv_usec = GET_JIFFIES_USEC();
Mikael Starvik51533b62005-07-27 11:44:44 -0700114}
115
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100116inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)
Mikael Starvik51533b62005-07-27 11:44:44 -0700117{
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100118 /* Compare jiffies. Takes care of wrapping */
119 if (time_before(t0->tv_jiff, t1->tv_jiff))
120 return -1;
121 else if (time_after(t0->tv_jiff, t1->tv_jiff))
122 return 1;
123
124 /* Compare us */
125 if (t0->tv_usec < t1->tv_usec)
126 return -1;
127 else if (t0->tv_usec > t1->tv_usec)
128 return 1;
129 return 0;
Mikael Starvik51533b62005-07-27 11:44:44 -0700130}
131
132/* Called with ints off */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100133inline void start_timer_trig(unsigned long delay_us)
Mikael Starvik51533b62005-07-27 11:44:44 -0700134{
135 reg_timer_rw_ack_intr ack_intr = { 0 };
136 reg_timer_rw_intr_mask intr_mask;
137 reg_timer_rw_trig trig;
138 reg_timer_rw_trig_cfg trig_cfg = { 0 };
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100139 reg_timer_r_time r_time0;
140 reg_timer_r_time r_time1;
141 unsigned char trig_wrap;
142 unsigned char time_wrap;
Mikael Starvik51533b62005-07-27 11:44:44 -0700143
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100144 r_time0 = REG_RD(timer, regi_timer0, r_time);
Mikael Starvik51533b62005-07-27 11:44:44 -0700145
146 D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
147 delay_us, freq_index, div));
148 /* Clear trig irq */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100149 intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700150 intr_mask.trig = 0;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100151 REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700152
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100153 /* Set timer values and check if trigger wraps. */
154 /* r_time is 100MHz (10 ns resolution) */
155 trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;
Mikael Starvik51533b62005-07-27 11:44:44 -0700156
157 timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
158 timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
159
160 /* Ack interrupt */
161 ack_intr.trig = 1;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100162 REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
Mikael Starvik51533b62005-07-27 11:44:44 -0700163
164 /* Start timer */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100165 REG_WR(timer, regi_timer0, rw_trig, trig);
Mikael Starvik51533b62005-07-27 11:44:44 -0700166 trig_cfg.tmr = regk_timer_time;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100167 REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
Mikael Starvik51533b62005-07-27 11:44:44 -0700168
169 /* Check if we have already passed the trig time */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100170 r_time1 = REG_RD(timer, regi_timer0, r_time);
171 time_wrap = r_time1 < r_time0;
172
173 if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700174 /* No, Enable trig irq */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100175 intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700176 intr_mask.trig = 1;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100177 REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700178 fast_timers_started++;
179 fast_timer_running = 1;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100180 } else {
Mikael Starvik51533b62005-07-27 11:44:44 -0700181 /* We have passed the time, disable trig point, ack intr */
182 trig_cfg.tmr = regk_timer_off;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100183 REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
184 REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
185 /* call the int routine */
186 INIT_WORK(&fast_work, timer_trig_handler);
187 schedule_work(&fast_work);
Mikael Starvik51533b62005-07-27 11:44:44 -0700188 }
189
190}
191
192/* In version 1.4 this function takes 27 - 50 us */
193void start_one_shot_timer(struct fast_timer *t,
194 fast_timer_function_type *function,
195 unsigned long data,
196 unsigned long delay_us,
197 const char *name)
198{
199 unsigned long flags;
200 struct fast_timer *tmp;
201
202 D1(printk("sft %s %d us\n", name, delay_us));
203
204 local_irq_save(flags);
205
206 do_gettimeofday_fast(&t->tv_set);
207 tmp = fast_timer_list;
208
209 SANITYCHECK({ /* Check so this is not in the list already... */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100210 while (tmp != NULL) {
211 if (tmp == t) {
212 printk(KERN_DEBUG
213 "timer name: %s data: 0x%08lX already "
214 "in list!\n", name, data);
215 sanity_failed++;
216 goto done;
217 } else
Mikael Starvik51533b62005-07-27 11:44:44 -0700218 tmp = tmp->next;
Mikael Starvik51533b62005-07-27 11:44:44 -0700219 }
220 tmp = fast_timer_list;
221 });
222
223 t->delay_us = delay_us;
224 t->function = function;
225 t->data = data;
226 t->name = name;
227
228 t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100229 t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
230 if (t->tv_expires.tv_usec > 1000000) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700231 t->tv_expires.tv_usec -= 1000000;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100232 t->tv_expires.tv_jiff += HZ;
Mikael Starvik51533b62005-07-27 11:44:44 -0700233 }
234#ifdef FAST_TIMER_LOG
235 timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
236#endif
237 fast_timers_added++;
238
239 /* Check if this should timeout before anything else */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100240 if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700241 /* Put first in list and modify the timer value */
242 t->prev = NULL;
243 t->next = fast_timer_list;
244 if (fast_timer_list)
Mikael Starvik51533b62005-07-27 11:44:44 -0700245 fast_timer_list->prev = t;
Mikael Starvik51533b62005-07-27 11:44:44 -0700246 fast_timer_list = t;
247#ifdef FAST_TIMER_LOG
248 timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
249#endif
250 start_timer_trig(delay_us);
251 } else {
252 /* Put in correct place in list */
253 while (tmp->next &&
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100254 fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
Mikael Starvik51533b62005-07-27 11:44:44 -0700255 tmp = tmp->next;
Mikael Starvik51533b62005-07-27 11:44:44 -0700256 /* Insert t after tmp */
257 t->prev = tmp;
258 t->next = tmp->next;
259 if (tmp->next)
260 {
261 tmp->next->prev = t;
262 }
263 tmp->next = t;
264 }
265
266 D2(printk("start_one_shot_timer: %d us done\n", delay_us));
267
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100268done:
Mikael Starvik51533b62005-07-27 11:44:44 -0700269 local_irq_restore(flags);
270} /* start_one_shot_timer */
271
272static inline int fast_timer_pending (const struct fast_timer * t)
273{
274 return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
275}
276
277static inline int detach_fast_timer (struct fast_timer *t)
278{
279 struct fast_timer *next, *prev;
280 if (!fast_timer_pending(t))
281 return 0;
282 next = t->next;
283 prev = t->prev;
284 if (next)
285 next->prev = prev;
286 if (prev)
287 prev->next = next;
288 else
289 fast_timer_list = next;
290 fast_timers_deleted++;
291 return 1;
292}
293
294int del_fast_timer(struct fast_timer * t)
295{
296 unsigned long flags;
297 int ret;
298
299 local_irq_save(flags);
300 ret = detach_fast_timer(t);
301 t->next = t->prev = NULL;
302 local_irq_restore(flags);
303 return ret;
304} /* del_fast_timer */
305
306
307/* Interrupt routines or functions called in interrupt context */
308
309/* Timer interrupt handler for trig interrupts */
310
311static irqreturn_t
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100312timer_trig_interrupt(int irq, void *dev_id)
Mikael Starvik51533b62005-07-27 11:44:44 -0700313{
314 reg_timer_r_masked_intr masked_intr;
Mikael Starvik51533b62005-07-27 11:44:44 -0700315 /* Check if the timer interrupt is for us (a trig int) */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100316 masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);
Mikael Starvik51533b62005-07-27 11:44:44 -0700317 if (!masked_intr.trig)
318 return IRQ_NONE;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100319 timer_trig_handler(NULL);
Mikael Starvik51533b62005-07-27 11:44:44 -0700320 return IRQ_HANDLED;
321}
322
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100323static void timer_trig_handler(struct work_struct *work)
Mikael Starvik51533b62005-07-27 11:44:44 -0700324{
325 reg_timer_rw_ack_intr ack_intr = { 0 };
326 reg_timer_rw_intr_mask intr_mask;
327 reg_timer_rw_trig_cfg trig_cfg = { 0 };
328 struct fast_timer *t;
329 unsigned long flags;
330
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100331 /* We keep interrupts disabled not only when we modify the
332 * fast timer list, but any time we hold a reference to a
333 * timer in the list, since del_fast_timer may be called
334 * from (another) interrupt context. Thus, the only time
335 * when interrupts are enabled is when calling the timer
336 * callback function.
337 */
Mikael Starvik51533b62005-07-27 11:44:44 -0700338 local_irq_save(flags);
339
340 /* Clear timer trig interrupt */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100341 intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700342 intr_mask.trig = 0;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100343 REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
Mikael Starvik51533b62005-07-27 11:44:44 -0700344
345 /* First stop timer, then ack interrupt */
346 /* Stop timer */
347 trig_cfg.tmr = regk_timer_off;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100348 REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
Mikael Starvik51533b62005-07-27 11:44:44 -0700349
350 /* Ack interrupt */
351 ack_intr.trig = 1;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100352 REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
Mikael Starvik51533b62005-07-27 11:44:44 -0700353
354 fast_timer_running = 0;
355 fast_timer_ints++;
356
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100357 fast_timer_function_type *f;
358 unsigned long d;
Mikael Starvik51533b62005-07-27 11:44:44 -0700359
360 t = fast_timer_list;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100361 while (t) {
362 struct fasttime_t tv;
Mikael Starvik51533b62005-07-27 11:44:44 -0700363
364 /* Has it really expired? */
365 do_gettimeofday_fast(&tv);
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100366 D1(printk(KERN_DEBUG
367 "t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));
Mikael Starvik51533b62005-07-27 11:44:44 -0700368
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100369 if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700370 /* Yes it has expired */
371#ifdef FAST_TIMER_LOG
372 timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
373#endif
374 fast_timers_expired++;
375
376 /* Remove this timer before call, since it may reuse the timer */
Mikael Starvik51533b62005-07-27 11:44:44 -0700377 if (t->prev)
Mikael Starvik51533b62005-07-27 11:44:44 -0700378 t->prev->next = t->next;
Mikael Starvik51533b62005-07-27 11:44:44 -0700379 else
Mikael Starvik51533b62005-07-27 11:44:44 -0700380 fast_timer_list = t->next;
Mikael Starvik51533b62005-07-27 11:44:44 -0700381 if (t->next)
Mikael Starvik51533b62005-07-27 11:44:44 -0700382 t->next->prev = t->prev;
Mikael Starvik51533b62005-07-27 11:44:44 -0700383 t->prev = NULL;
384 t->next = NULL;
Mikael Starvik51533b62005-07-27 11:44:44 -0700385
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100386 /* Save function callback data before enabling
387 * interrupts, since the timer may be removed and we
388 * don't know how it was allocated (e.g. ->function
389 * and ->data may become overwritten after deletion
390 * if the timer was stack-allocated).
391 */
392 f = t->function;
393 d = t->data;
394
395 if (f != NULL) {
396 /* Run the callback function with interrupts
397 * enabled. */
398 local_irq_restore(flags);
399 f(d);
400 local_irq_save(flags);
401 } else
Mikael Starvik51533b62005-07-27 11:44:44 -0700402 DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100403 } else {
Mikael Starvik51533b62005-07-27 11:44:44 -0700404 /* Timer is to early, let's set it again using the normal routines */
405 D1(printk(".\n"));
406 }
407
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100408 t = fast_timer_list;
409 if (t != NULL) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700410 /* Start next timer.. */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100411 long us = 0;
412 struct fasttime_t tv;
Mikael Starvik51533b62005-07-27 11:44:44 -0700413
414 do_gettimeofday_fast(&tv);
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100415
416 /* time_after_eq takes care of wrapping */
417 if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
418 us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
419 1000000 / HZ + t->tv_expires.tv_usec -
420 tv.tv_usec);
421
422 if (us > 0) {
423 if (!fast_timer_running) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700424#ifdef FAST_TIMER_LOG
425 timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
426#endif
427 start_timer_trig(us);
428 }
Mikael Starvik51533b62005-07-27 11:44:44 -0700429 break;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100430 } else {
Mikael Starvik51533b62005-07-27 11:44:44 -0700431 /* Timer already expired, let's handle it better late than never.
432 * The normal loop handles it
433 */
434 D1(printk("e! %d\n", us));
435 }
436 }
Mikael Starvik51533b62005-07-27 11:44:44 -0700437 }
438
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100439 local_irq_restore(flags);
440
441 if (!t)
Mikael Starvik51533b62005-07-27 11:44:44 -0700442 D1(printk("ttrig stop!\n"));
Mikael Starvik51533b62005-07-27 11:44:44 -0700443}
444
445static void wake_up_func(unsigned long data)
446{
Mikael Starvik51533b62005-07-27 11:44:44 -0700447 wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data;
Mikael Starvik51533b62005-07-27 11:44:44 -0700448 wake_up(sleep_wait_p);
449}
450
451
452/* Useful API */
453
454void schedule_usleep(unsigned long us)
455{
456 struct fast_timer t;
Mikael Starvik51533b62005-07-27 11:44:44 -0700457 wait_queue_head_t sleep_wait;
458 init_waitqueue_head(&sleep_wait);
Mikael Starvik51533b62005-07-27 11:44:44 -0700459
460 D1(printk("schedule_usleep(%d)\n", us));
Mikael Starvik51533b62005-07-27 11:44:44 -0700461 start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
462 "usleep");
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100463 /* Uninterruptible sleep on the fast timer. (The condition is
464 * somewhat redundant since the timer is what wakes us up.) */
465 wait_event(sleep_wait, !fast_timer_pending(&t));
466
Mikael Starvik51533b62005-07-27 11:44:44 -0700467 D1(printk("done schedule_usleep(%d)\n", us));
Mikael Starvik51533b62005-07-27 11:44:44 -0700468}
469
470#ifdef CONFIG_PROC_FS
471static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
Robert P. J. Day7a3e9652007-05-06 14:50:56 -0700472 ,int *eof, void *data_unused);
Mikael Starvik51533b62005-07-27 11:44:44 -0700473static struct proc_dir_entry *fasttimer_proc_entry;
Mikael Starvik51533b62005-07-27 11:44:44 -0700474#endif /* CONFIG_PROC_FS */
475
476#ifdef CONFIG_PROC_FS
477
478/* This value is very much based on testing */
479#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
480
481static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
Robert P. J. Day7a3e9652007-05-06 14:50:56 -0700482 ,int *eof, void *data_unused)
Mikael Starvik51533b62005-07-27 11:44:44 -0700483{
484 unsigned long flags;
485 int i = 0;
486 int num_to_show;
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100487 struct fasttime_t tv;
Mikael Starvik51533b62005-07-27 11:44:44 -0700488 struct fast_timer *t, *nextt;
489 static char *bigbuf = NULL;
490 static unsigned long used;
491
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100492 if (!bigbuf) {
493 bigbuf = vmalloc(BIG_BUF_SIZE);
494 if (!bigbuf) {
495 used = 0;
496 if (buf)
497 buf[0] = '\0';
498 return 0;
499 }
500 }
Mikael Starvik51533b62005-07-27 11:44:44 -0700501
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100502 if (!offset || !used) {
Mikael Starvik51533b62005-07-27 11:44:44 -0700503 do_gettimeofday_fast(&tv);
504
505 used = 0;
506 used += sprintf(bigbuf + used, "Fast timers added: %i\n",
507 fast_timers_added);
508 used += sprintf(bigbuf + used, "Fast timers started: %i\n",
509 fast_timers_started);
510 used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
511 fast_timer_ints);
512 used += sprintf(bigbuf + used, "Fast timers expired: %i\n",
513 fast_timers_expired);
514 used += sprintf(bigbuf + used, "Fast timers deleted: %i\n",
515 fast_timers_deleted);
516 used += sprintf(bigbuf + used, "Fast timer running: %s\n",
517 fast_timer_running ? "yes" : "no");
518 used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n",
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100519 (unsigned long)tv.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700520 (unsigned long)tv.tv_usec);
521#ifdef FAST_TIMER_SANITY_CHECKS
522 used += sprintf(bigbuf + used, "Sanity failed: %i\n",
523 sanity_failed);
524#endif
525 used += sprintf(bigbuf + used, "\n");
526
527#ifdef DEBUG_LOG_INCLUDED
528 {
529 int end_i = debug_log_cnt;
530 i = 0;
531
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100532 if (debug_log_cnt_wrapped)
Mikael Starvik51533b62005-07-27 11:44:44 -0700533 i = debug_log_cnt;
Mikael Starvik51533b62005-07-27 11:44:44 -0700534
535 while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
536 used+100 < BIG_BUF_SIZE)
537 {
538 used += sprintf(bigbuf + used, debug_log_string[i],
539 debug_log_value[i]);
540 i = (i+1) % DEBUG_LOG_MAX;
541 }
542 }
543 used += sprintf(bigbuf + used, "\n");
544#endif
545
546 num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
547 NUM_TIMER_STATS);
548 used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
549 for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
550 {
551 int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
552
553#if 1 //ndef FAST_TIMER_LOG
554 used += sprintf(bigbuf + used, "div: %i delay: %i"
555 "\n",
556 timer_div_settings[cur],
557 timer_delay_settings[cur]
558 );
559#endif
560#ifdef FAST_TIMER_LOG
561 t = &timer_started_log[cur];
562 used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
563 "d: %6li us data: 0x%08lX"
564 "\n",
565 t->name,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100566 (unsigned long)t->tv_set.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700567 (unsigned long)t->tv_set.tv_usec,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100568 (unsigned long)t->tv_expires.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700569 (unsigned long)t->tv_expires.tv_usec,
570 t->delay_us,
571 t->data
572 );
573#endif
574 }
575 used += sprintf(bigbuf + used, "\n");
576
577#ifdef FAST_TIMER_LOG
578 num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
579 NUM_TIMER_STATS);
580 used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
581 for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
582 {
583 t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
584 used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
585 "d: %6li us data: 0x%08lX"
586 "\n",
587 t->name,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100588 (unsigned long)t->tv_set.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700589 (unsigned long)t->tv_set.tv_usec,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100590 (unsigned long)t->tv_expires.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700591 (unsigned long)t->tv_expires.tv_usec,
592 t->delay_us,
593 t->data
594 );
595 }
596 used += sprintf(bigbuf + used, "\n");
597
598 num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
599 NUM_TIMER_STATS);
600 used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
601 for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
602 {
603 t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
604 used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
605 "d: %6li us data: 0x%08lX"
606 "\n",
607 t->name,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100608 (unsigned long)t->tv_set.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700609 (unsigned long)t->tv_set.tv_usec,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100610 (unsigned long)t->tv_expires.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700611 (unsigned long)t->tv_expires.tv_usec,
612 t->delay_us,
613 t->data
614 );
615 }
616 used += sprintf(bigbuf + used, "\n");
617#endif
618
619 used += sprintf(bigbuf + used, "Active timers:\n");
620 local_irq_save(flags);
Mikael Starvik51533b62005-07-27 11:44:44 -0700621 t = fast_timer_list;
622 while (t != NULL && (used+100 < BIG_BUF_SIZE))
623 {
624 nextt = t->next;
625 local_irq_restore(flags);
626 used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100627 "d: %6li us data: 0x%08lX"
628/* " func: 0x%08lX" */
629 "\n",
630 t->name,
631 (unsigned long)t->tv_set.tv_jiff,
632 (unsigned long)t->tv_set.tv_usec,
633 (unsigned long)t->tv_expires.tv_jiff,
634 (unsigned long)t->tv_expires.tv_usec,
Mikael Starvik51533b62005-07-27 11:44:44 -0700635 t->delay_us,
636 t->data
637/* , t->function */
638 );
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100639 local_irq_save(flags);
Mikael Starvik51533b62005-07-27 11:44:44 -0700640 if (t->next != nextt)
641 {
642 printk("timer removed!\n");
643 }
644 t = nextt;
645 }
646 local_irq_restore(flags);
647 }
648
649 if (used - offset < len)
650 {
651 len = used - offset;
652 }
653
654 memcpy(buf, bigbuf + offset, len);
655 *start = buf;
Mikael Starvik51533b62005-07-27 11:44:44 -0700656 *eof = 1;
Mikael Starvik51533b62005-07-27 11:44:44 -0700657
658 return len;
659}
660#endif /* PROC_FS */
661
662#ifdef FAST_TIMER_TEST
663static volatile unsigned long i = 0;
664static volatile int num_test_timeout = 0;
665static struct fast_timer tr[10];
666static int exp_num[10];
667
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100668static struct fasttime_t tv_exp[100];
Mikael Starvik51533b62005-07-27 11:44:44 -0700669
670static void test_timeout(unsigned long data)
671{
672 do_gettimeofday_fast(&tv_exp[data]);
673 exp_num[data] = num_test_timeout;
674
675 num_test_timeout++;
676}
677
678static void test_timeout1(unsigned long data)
679{
680 do_gettimeofday_fast(&tv_exp[data]);
681 exp_num[data] = num_test_timeout;
682 if (data < 7)
683 {
684 start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
685 i++;
686 }
687 num_test_timeout++;
688}
689
690DP(
691static char buf0[2000];
692static char buf1[2000];
693static char buf2[2000];
694static char buf3[2000];
695static char buf4[2000];
696);
697
698static char buf5[6000];
699static int j_u[1000];
700
701static void fast_timer_test(void)
702{
703 int prev_num;
704 int j;
705
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100706 struct fasttime_t tv, tv0, tv1, tv2;
Mikael Starvik51533b62005-07-27 11:44:44 -0700707
708 printk("fast_timer_test() start\n");
709 do_gettimeofday_fast(&tv);
710
711 for (j = 0; j < 1000; j++)
712 {
713 j_u[j] = GET_JIFFIES_USEC();
714 }
715 for (j = 0; j < 100; j++)
716 {
717 do_gettimeofday_fast(&tv_exp[j]);
718 }
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100719 printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec);
Mikael Starvik51533b62005-07-27 11:44:44 -0700720
721 for (j = 0; j < 1000; j++)
722 {
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100723 printk(KERN_DEBUG "%i %i %i %i %i\n",
724 j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
Mikael Starvik51533b62005-07-27 11:44:44 -0700725 j += 4;
726 }
727 for (j = 0; j < 100; j++)
728 {
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100729 printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
730 tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
731 tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
732 tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
733 tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
734 tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
Mikael Starvik51533b62005-07-27 11:44:44 -0700735 j += 4;
736 }
737 do_gettimeofday_fast(&tv0);
738 start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
739 DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
740 i++;
741 start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
742 DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
743 i++;
744 start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
745 DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
746 i++;
747 start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
748 DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
749 i++;
750 start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
751 DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
752 i++;
753 do_gettimeofday_fast(&tv1);
754
755 proc_fasttimer_read(buf5, NULL, 0, 0, 0);
756
757 prev_num = num_test_timeout;
758 while (num_test_timeout < i)
759 {
760 if (num_test_timeout != prev_num)
Mikael Starvik51533b62005-07-27 11:44:44 -0700761 prev_num = num_test_timeout;
Mikael Starvik51533b62005-07-27 11:44:44 -0700762 }
763 do_gettimeofday_fast(&tv2);
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100764 printk(KERN_INFO "Timers started %is %06i\n",
765 tv0.tv_jiff, tv0.tv_usec);
766 printk(KERN_INFO "Timers started at %is %06i\n",
767 tv1.tv_jiff, tv1.tv_usec);
768 printk(KERN_INFO "Timers done %is %06i\n",
769 tv2.tv_jiff, tv2.tv_usec);
Mikael Starvik51533b62005-07-27 11:44:44 -0700770 DP(printk("buf0:\n");
771 printk(buf0);
772 printk("buf1:\n");
773 printk(buf1);
774 printk("buf2:\n");
775 printk(buf2);
776 printk("buf3:\n");
777 printk(buf3);
778 printk("buf4:\n");
779 printk(buf4);
780 );
781 printk("buf5:\n");
782 printk(buf5);
783
784 printk("timers set:\n");
785 for(j = 0; j<i; j++)
786 {
787 struct fast_timer *t = &tr[j];
788 printk("%-10s set: %6is %06ius exp: %6is %06ius "
789 "data: 0x%08X func: 0x%08X\n",
790 t->name,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100791 t->tv_set.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700792 t->tv_set.tv_usec,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100793 t->tv_expires.tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700794 t->tv_expires.tv_usec,
795 t->data,
796 t->function
797 );
798
799 printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",
800 t->delay_us,
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100801 tv_exp[j].tv_jiff,
Mikael Starvik51533b62005-07-27 11:44:44 -0700802 tv_exp[j].tv_usec,
803 exp_num[j],
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100804 (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
805 1000000 + tv_exp[j].tv_usec -
806 t->tv_expires.tv_usec);
Mikael Starvik51533b62005-07-27 11:44:44 -0700807 }
808 proc_fasttimer_read(buf5, NULL, 0, 0, 0);
809 printk("buf5 after all done:\n");
810 printk(buf5);
811 printk("fast_timer_test() done\n");
812}
813#endif
814
815
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100816int fast_timer_init(void)
Mikael Starvik51533b62005-07-27 11:44:44 -0700817{
818 /* For some reason, request_irq() hangs when called froom time_init() */
819 if (!fast_timer_is_init)
820 {
821 printk("fast_timer_init()\n");
822
823#ifdef CONFIG_PROC_FS
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100824 fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0);
825 if (fasttimer_proc_entry)
826 fasttimer_proc_entry->read_proc = proc_fasttimer_read;
Mikael Starvik51533b62005-07-27 11:44:44 -0700827#endif /* PROC_FS */
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100828 if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
829 IRQF_SHARED | IRQF_DISABLED,
830 "fast timer int", &fast_timer_list))
831 printk(KERN_ERR "err: fasttimer irq\n");
Mikael Starvik51533b62005-07-27 11:44:44 -0700832 fast_timer_is_init = 1;
833#ifdef FAST_TIMER_TEST
834 printk("do test\n");
835 fast_timer_test();
836#endif
837 }
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100838 return 0;
Mikael Starvik51533b62005-07-27 11:44:44 -0700839}
Jesper Nilssonec87ee22007-11-30 17:46:11 +0100840__initcall(fast_timer_init);