diff options
author | Jesper Nilsson <jesper.nilsson@axis.com> | 2007-11-14 20:01:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-14 21:45:47 -0500 |
commit | d8e5219f9f5ca7518eb820db9f3d287a1d46fcf5 (patch) | |
tree | af996eb526010d0f5106df12de646cc1dd64b29e | |
parent | 3244c77bd3460e9701ffeecc2452d7f2ee17106c (diff) |
CRISv10 improve and bugfix fasttimer
Improve and bugfix CRIS v10 fast timers.
- irq_handler_t now only takes two arguments.
- Keep interrupts disabled as long as we have a reference to the
fasttimer list and only enable them while doing the callback.
del_fast_timer may be called from other interrupt context.
- Fix bug where debug code could return without calling local_irq_restore.
- Use jiffies instead of usec (change from struct timeval to fasttime_t).
- Don't initialize static variables to zero.
- Remove obsolete #ifndef DECLARE_WAITQUEUE code.
- fast_timer_init should be __initcall.
- Change status/debug variables to unsigned.
- Remove CVS log and CVS id.
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Mikael Starvik <mikael.starvik@axis.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/cris/arch-v10/kernel/fasttimer.c | 315 | ||||
-rw-r--r-- | include/asm-cris/fasttimer.h | 16 |
2 files changed, 124 insertions, 207 deletions
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index d3ea052e5ee1..645d7059b401 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c | |||
@@ -1,97 +1,9 @@ | |||
1 | /* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $ | 1 | /* |
2 | * linux/arch/cris/kernel/fasttimer.c | 2 | * linux/arch/cris/kernel/fasttimer.c |
3 | * | 3 | * |
4 | * Fast timers for ETRAX100/ETRAX100LX | 4 | * Fast timers for ETRAX100/ETRAX100LX |
5 | * This may be useful in other OS than Linux so use 2 space indentation... | ||
6 | * | 5 | * |
7 | * $Log: fasttimer.c,v $ | 6 | * Copyright (C) 2000-2007 Axis Communications AB, Lund, Sweden |
8 | * Revision 1.9 2005/03/04 08:16:16 starvik | ||
9 | * Merge of Linux 2.6.11. | ||
10 | * | ||
11 | * Revision 1.8 2005/01/05 06:09:29 starvik | ||
12 | * cli()/sti() will be obsolete in 2.6.11. | ||
13 | * | ||
14 | * Revision 1.7 2005/01/03 13:35:46 starvik | ||
15 | * Removed obsolete stuff. | ||
16 | * Mark fast timer IRQ as not shared. | ||
17 | * | ||
18 | * Revision 1.6 2004/05/14 10:18:39 starvik | ||
19 | * Export fast_timer_list | ||
20 | * | ||
21 | * Revision 1.5 2004/05/14 07:58:01 starvik | ||
22 | * Merge of changes from 2.4 | ||
23 | * | ||
24 | * Revision 1.4 2003/07/04 08:27:41 starvik | ||
25 | * Merge of Linux 2.5.74 | ||
26 | * | ||
27 | * Revision 1.3 2002/12/12 08:26:32 starvik | ||
28 | * Don't use C-comments inside CVS comments | ||
29 | * | ||
30 | * Revision 1.2 2002/12/11 15:42:02 starvik | ||
31 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
32 | * | ||
33 | * Revision 1.1 2002/11/18 07:58:06 starvik | ||
34 | * Fast timers (from Linux 2.4) | ||
35 | * | ||
36 | * Revision 1.5 2002/10/15 06:21:39 starvik | ||
37 | * Added call to init_waitqueue_head | ||
38 | * | ||
39 | * Revision 1.4 2002/05/28 17:47:59 johana | ||
40 | * Added del_fast_timer() | ||
41 | * | ||
42 | * Revision 1.3 2002/05/28 16:16:07 johana | ||
43 | * Handle empty fast_timer_list | ||
44 | * | ||
45 | * Revision 1.2 2002/05/27 15:38:42 johana | ||
46 | * Made it compile without warnings on Linux 2.4. | ||
47 | * (includes, wait_queue, PROC_FS and snprintf) | ||
48 | * | ||
49 | * Revision 1.1 2002/05/27 15:32:25 johana | ||
50 | * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. | ||
51 | * | ||
52 | * Revision 1.8 2001/11/27 13:50:40 pkj | ||
53 | * Disable interrupts while stopping the timer and while modifying the | ||
54 | * list of active timers in timer1_handler() as it may be interrupted | ||
55 | * by other interrupts (e.g., the serial interrupt) which may add fast | ||
56 | * timers. | ||
57 | * | ||
58 | * Revision 1.7 2001/11/22 11:50:32 pkj | ||
59 | * * Only store information about the last 16 timers. | ||
60 | * * proc_fasttimer_read() now uses an allocated buffer, since it | ||
61 | * requires more space than just a page even for only writing the | ||
62 | * last 16 timers. The buffer is only allocated on request, so | ||
63 | * unless /proc/fasttimer is read, it is never allocated. | ||
64 | * * Renamed fast_timer_started to fast_timers_started to match | ||
65 | * fast_timers_added and fast_timers_expired. | ||
66 | * * Some clean-up. | ||
67 | * | ||
68 | * Revision 1.6 2000/12/13 14:02:08 johana | ||
69 | * Removed volatile for fast_timer_list | ||
70 | * | ||
71 | * Revision 1.5 2000/12/13 13:55:35 johana | ||
72 | * Added DEBUG_LOG, added som cli() and cleanup | ||
73 | * | ||
74 | * Revision 1.4 2000/12/05 13:48:50 johana | ||
75 | * Added range check when writing proc file, modified timer int handling | ||
76 | * | ||
77 | * Revision 1.3 2000/11/23 10:10:20 johana | ||
78 | * More debug/logging possibilities. | ||
79 | * Moved GET_JIFFIES_USEC() to timex.h and time.c | ||
80 | * | ||
81 | * Revision 1.2 2000/11/01 13:41:04 johana | ||
82 | * Clean up and bugfixes. | ||
83 | * Created new do_gettimeofday_fast() that gets a timeval struct | ||
84 | * with time based on jiffies and *R_TIMER0_DATA, uses a table | ||
85 | * for fast conversion of timer value to microseconds. | ||
86 | * (Much faster the standard do_gettimeofday() and we don't really | ||
87 | * want to use the true time - we want the "uptime" so timers don't screw up | ||
88 | * when we change the time. | ||
89 | * TODO: Add efficient support for continuous timers as well. | ||
90 | * | ||
91 | * Revision 1.1 2000/10/26 15:49:16 johana | ||
92 | * Added fasttimer, highresolution timers. | ||
93 | * | ||
94 | * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden | ||
95 | */ | 7 | */ |
96 | 8 | ||
97 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
@@ -125,7 +37,7 @@ | |||
125 | 37 | ||
126 | #ifdef FAST_TIMER_SANITY_CHECKS | 38 | #ifdef FAST_TIMER_SANITY_CHECKS |
127 | #define SANITYCHECK(x) x | 39 | #define SANITYCHECK(x) x |
128 | static int sanity_failed = 0; | 40 | static int sanity_failed; |
129 | #else | 41 | #else |
130 | #define SANITYCHECK(x) | 42 | #define SANITYCHECK(x) |
131 | #endif | 43 | #endif |
@@ -136,13 +48,13 @@ static int sanity_failed = 0; | |||
136 | 48 | ||
137 | #define __INLINE__ inline | 49 | #define __INLINE__ inline |
138 | 50 | ||
139 | static int fast_timer_running = 0; | 51 | static unsigned int fast_timer_running; |
140 | static int fast_timers_added = 0; | 52 | static unsigned int fast_timers_added; |
141 | static int fast_timers_started = 0; | 53 | static unsigned int fast_timers_started; |
142 | static int fast_timers_expired = 0; | 54 | static unsigned int fast_timers_expired; |
143 | static int fast_timers_deleted = 0; | 55 | static unsigned int fast_timers_deleted; |
144 | static int fast_timer_is_init = 0; | 56 | static unsigned int fast_timer_is_init; |
145 | static int fast_timer_ints = 0; | 57 | static unsigned int fast_timer_ints; |
146 | 58 | ||
147 | struct fast_timer *fast_timer_list = NULL; | 59 | struct fast_timer *fast_timer_list = NULL; |
148 | 60 | ||
@@ -150,8 +62,8 @@ struct fast_timer *fast_timer_list = NULL; | |||
150 | #define DEBUG_LOG_MAX 128 | 62 | #define DEBUG_LOG_MAX 128 |
151 | static const char * debug_log_string[DEBUG_LOG_MAX]; | 63 | static const char * debug_log_string[DEBUG_LOG_MAX]; |
152 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; | 64 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; |
153 | static int debug_log_cnt = 0; | 65 | static unsigned int debug_log_cnt; |
154 | static int debug_log_cnt_wrapped = 0; | 66 | static unsigned int debug_log_cnt_wrapped; |
155 | 67 | ||
156 | #define DEBUG_LOG(string, value) \ | 68 | #define DEBUG_LOG(string, value) \ |
157 | { \ | 69 | { \ |
@@ -206,42 +118,26 @@ int timer_freq_settings[NUM_TIMER_STATS]; | |||
206 | int timer_delay_settings[NUM_TIMER_STATS]; | 118 | int timer_delay_settings[NUM_TIMER_STATS]; |
207 | 119 | ||
208 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ | 120 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ |
209 | void __INLINE__ do_gettimeofday_fast(struct timeval *tv) | 121 | void __INLINE__ do_gettimeofday_fast(struct fasttime_t *tv) |
210 | { | 122 | { |
211 | unsigned long sec = jiffies; | 123 | tv->tv_jiff = jiffies; |
212 | unsigned long usec = GET_JIFFIES_USEC(); | 124 | tv->tv_usec = GET_JIFFIES_USEC(); |
213 | |||
214 | usec += (sec % HZ) * (1000000 / HZ); | ||
215 | sec = sec / HZ; | ||
216 | |||
217 | if (usec > 1000000) | ||
218 | { | ||
219 | usec -= 1000000; | ||
220 | sec++; | ||
221 | } | ||
222 | tv->tv_sec = sec; | ||
223 | tv->tv_usec = usec; | ||
224 | } | 125 | } |
225 | 126 | ||
226 | int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) | 127 | int __INLINE__ timeval_cmp(struct fasttime_t *t0, struct fasttime_t *t1) |
227 | { | 128 | { |
228 | if (t0->tv_sec < t1->tv_sec) | 129 | /* Compare jiffies. Takes care of wrapping */ |
229 | { | 130 | if (time_before(t0->tv_jiff, t1->tv_jiff)) |
230 | return -1; | 131 | return -1; |
231 | } | 132 | else if (time_after(t0->tv_jiff, t1->tv_jiff)) |
232 | else if (t0->tv_sec > t1->tv_sec) | 133 | return 1; |
233 | { | 134 | |
234 | return 1; | 135 | /* Compare us */ |
235 | } | 136 | if (t0->tv_usec < t1->tv_usec) |
236 | if (t0->tv_usec < t1->tv_usec) | 137 | return -1; |
237 | { | 138 | else if (t0->tv_usec > t1->tv_usec) |
238 | return -1; | 139 | return 1; |
239 | } | 140 | return 0; |
240 | else if (t0->tv_usec > t1->tv_usec) | ||
241 | { | ||
242 | return 1; | ||
243 | } | ||
244 | return 0; | ||
245 | } | 141 | } |
246 | 142 | ||
247 | void __INLINE__ start_timer1(unsigned long delay_us) | 143 | void __INLINE__ start_timer1(unsigned long delay_us) |
@@ -285,7 +181,7 @@ void __INLINE__ start_timer1(unsigned long delay_us) | |||
285 | timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; | 181 | timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; |
286 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; | 182 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; |
287 | 183 | ||
288 | D1(printk("start_timer1 : %d us freq: %i div: %i\n", | 184 | D1(printk(KERN_DEBUG "start_timer1 : %d us freq: %i div: %i\n", |
289 | delay_us, freq_index, div)); | 185 | delay_us, freq_index, div)); |
290 | /* Clear timer1 irq */ | 186 | /* Clear timer1 irq */ |
291 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); | 187 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); |
@@ -340,7 +236,7 @@ void start_one_shot_timer(struct fast_timer *t, | |||
340 | printk(KERN_WARNING | 236 | printk(KERN_WARNING |
341 | "timer name: %s data: 0x%08lX already in list!\n", name, data); | 237 | "timer name: %s data: 0x%08lX already in list!\n", name, data); |
342 | sanity_failed++; | 238 | sanity_failed++; |
343 | return; | 239 | goto done; |
344 | } | 240 | } |
345 | else | 241 | else |
346 | { | 242 | { |
@@ -356,11 +252,11 @@ void start_one_shot_timer(struct fast_timer *t, | |||
356 | t->name = name; | 252 | t->name = name; |
357 | 253 | ||
358 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; | 254 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; |
359 | t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; | 255 | t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ; |
360 | if (t->tv_expires.tv_usec > 1000000) | 256 | if (t->tv_expires.tv_usec > 1000000) |
361 | { | 257 | { |
362 | t->tv_expires.tv_usec -= 1000000; | 258 | t->tv_expires.tv_usec -= 1000000; |
363 | t->tv_expires.tv_sec++; | 259 | t->tv_expires.tv_jiff += HZ; |
364 | } | 260 | } |
365 | #ifdef FAST_TIMER_LOG | 261 | #ifdef FAST_TIMER_LOG |
366 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; | 262 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; |
@@ -401,6 +297,7 @@ void start_one_shot_timer(struct fast_timer *t, | |||
401 | 297 | ||
402 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); | 298 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); |
403 | 299 | ||
300 | done: | ||
404 | local_irq_restore(flags); | 301 | local_irq_restore(flags); |
405 | } /* start_one_shot_timer */ | 302 | } /* start_one_shot_timer */ |
406 | 303 | ||
@@ -444,11 +341,18 @@ int del_fast_timer(struct fast_timer * t) | |||
444 | /* Timer 1 interrupt handler */ | 341 | /* Timer 1 interrupt handler */ |
445 | 342 | ||
446 | static irqreturn_t | 343 | static irqreturn_t |
447 | timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | 344 | timer1_handler(int irq, void *dev_id) |
448 | { | 345 | { |
449 | struct fast_timer *t; | 346 | struct fast_timer *t; |
450 | unsigned long flags; | 347 | unsigned long flags; |
451 | 348 | ||
349 | /* We keep interrupts disabled not only when we modify the | ||
350 | * fast timer list, but any time we hold a reference to a | ||
351 | * timer in the list, since del_fast_timer may be called | ||
352 | * from (another) interrupt context. Thus, the only time | ||
353 | * when interrupts are enabled is when calling the timer | ||
354 | * callback function. | ||
355 | */ | ||
452 | local_irq_save(flags); | 356 | local_irq_save(flags); |
453 | 357 | ||
454 | /* Clear timer1 irq */ | 358 | /* Clear timer1 irq */ |
@@ -466,16 +370,17 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
466 | fast_timer_running = 0; | 370 | fast_timer_running = 0; |
467 | fast_timer_ints++; | 371 | fast_timer_ints++; |
468 | 372 | ||
469 | local_irq_restore(flags); | ||
470 | |||
471 | t = fast_timer_list; | 373 | t = fast_timer_list; |
472 | while (t) | 374 | while (t) |
473 | { | 375 | { |
474 | struct timeval tv; | 376 | struct fasttime_t tv; |
377 | fast_timer_function_type *f; | ||
378 | unsigned long d; | ||
475 | 379 | ||
476 | /* Has it really expired? */ | 380 | /* Has it really expired? */ |
477 | do_gettimeofday_fast(&tv); | 381 | do_gettimeofday_fast(&tv); |
478 | D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); | 382 | D1(printk(KERN_DEBUG "t: %is %06ius\n", |
383 | tv.tv_jiff, tv.tv_usec)); | ||
479 | 384 | ||
480 | if (timeval_cmp(&t->tv_expires, &tv) <= 0) | 385 | if (timeval_cmp(&t->tv_expires, &tv) <= 0) |
481 | { | 386 | { |
@@ -486,7 +391,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
486 | fast_timers_expired++; | 391 | fast_timers_expired++; |
487 | 392 | ||
488 | /* Remove this timer before call, since it may reuse the timer */ | 393 | /* Remove this timer before call, since it may reuse the timer */ |
489 | local_irq_save(flags); | ||
490 | if (t->prev) | 394 | if (t->prev) |
491 | { | 395 | { |
492 | t->prev->next = t->next; | 396 | t->prev->next = t->next; |
@@ -501,16 +405,23 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
501 | } | 405 | } |
502 | t->prev = NULL; | 406 | t->prev = NULL; |
503 | t->next = NULL; | 407 | t->next = NULL; |
504 | local_irq_restore(flags); | ||
505 | 408 | ||
506 | if (t->function != NULL) | 409 | /* Save function callback data before enabling |
507 | { | 410 | * interrupts, since the timer may be removed and |
508 | t->function(t->data); | 411 | * we don't know how it was allocated |
509 | } | 412 | * (e.g. ->function and ->data may become overwritten |
510 | else | 413 | * after deletion if the timer was stack-allocated). |
511 | { | 414 | */ |
415 | f = t->function; | ||
416 | d = t->data; | ||
417 | |||
418 | if (f != NULL) { | ||
419 | /* Run callback with interrupts enabled. */ | ||
420 | local_irq_restore(flags); | ||
421 | f(d); | ||
422 | local_irq_save(flags); | ||
423 | } else | ||
512 | DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); | 424 | DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); |
513 | } | ||
514 | } | 425 | } |
515 | else | 426 | else |
516 | { | 427 | { |
@@ -518,16 +429,20 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
518 | D1(printk(".\n")); | 429 | D1(printk(".\n")); |
519 | } | 430 | } |
520 | 431 | ||
521 | local_irq_save(flags); | ||
522 | if ((t = fast_timer_list) != NULL) | 432 | if ((t = fast_timer_list) != NULL) |
523 | { | 433 | { |
524 | /* Start next timer.. */ | 434 | /* Start next timer.. */ |
525 | long us; | 435 | long us = 0; |
526 | struct timeval tv; | 436 | struct fasttime_t tv; |
527 | 437 | ||
528 | do_gettimeofday_fast(&tv); | 438 | do_gettimeofday_fast(&tv); |
529 | us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + | 439 | |
530 | t->tv_expires.tv_usec - tv.tv_usec); | 440 | /* time_after_eq takes care of wrapping */ |
441 | if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff)) | ||
442 | us = ((t->tv_expires.tv_jiff - tv.tv_jiff) * | ||
443 | 1000000 / HZ + t->tv_expires.tv_usec - | ||
444 | tv.tv_usec); | ||
445 | |||
531 | if (us > 0) | 446 | if (us > 0) |
532 | { | 447 | { |
533 | if (!fast_timer_running) | 448 | if (!fast_timer_running) |
@@ -537,7 +452,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
537 | #endif | 452 | #endif |
538 | start_timer1(us); | 453 | start_timer1(us); |
539 | } | 454 | } |
540 | local_irq_restore(flags); | ||
541 | break; | 455 | break; |
542 | } | 456 | } |
543 | else | 457 | else |
@@ -548,9 +462,10 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | |||
548 | D1(printk("e! %d\n", us)); | 462 | D1(printk("e! %d\n", us)); |
549 | } | 463 | } |
550 | } | 464 | } |
551 | local_irq_restore(flags); | ||
552 | } | 465 | } |
553 | 466 | ||
467 | local_irq_restore(flags); | ||
468 | |||
554 | if (!t) | 469 | if (!t) |
555 | { | 470 | { |
556 | D1(printk("t1 stop!\n")); | 471 | D1(printk("t1 stop!\n")); |
@@ -575,28 +490,17 @@ static void wake_up_func(unsigned long data) | |||
575 | void schedule_usleep(unsigned long us) | 490 | void schedule_usleep(unsigned long us) |
576 | { | 491 | { |
577 | struct fast_timer t; | 492 | struct fast_timer t; |
578 | #ifdef DECLARE_WAITQUEUE | ||
579 | wait_queue_head_t sleep_wait; | 493 | wait_queue_head_t sleep_wait; |
580 | init_waitqueue_head(&sleep_wait); | 494 | init_waitqueue_head(&sleep_wait); |
581 | { | ||
582 | DECLARE_WAITQUEUE(wait, current); | ||
583 | #else | ||
584 | struct wait_queue *sleep_wait = NULL; | ||
585 | struct wait_queue wait = { current, NULL }; | ||
586 | #endif | ||
587 | 495 | ||
588 | D1(printk("schedule_usleep(%d)\n", us)); | 496 | D1(printk("schedule_usleep(%d)\n", us)); |
589 | add_wait_queue(&sleep_wait, &wait); | ||
590 | set_current_state(TASK_INTERRUPTIBLE); | ||
591 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, | 497 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, |
592 | "usleep"); | 498 | "usleep"); |
593 | schedule(); | 499 | /* Uninterruptible sleep on the fast timer. (The condition is somewhat |
594 | set_current_state(TASK_RUNNING); | 500 | * redundant since the timer is what wakes us up.) */ |
595 | remove_wait_queue(&sleep_wait, &wait); | 501 | wait_event(sleep_wait, !fast_timer_pending(&t)); |
502 | |||
596 | D1(printk("done schedule_usleep(%d)\n", us)); | 503 | D1(printk("done schedule_usleep(%d)\n", us)); |
597 | #ifdef DECLARE_WAITQUEUE | ||
598 | } | ||
599 | #endif | ||
600 | } | 504 | } |
601 | 505 | ||
602 | #ifdef CONFIG_PROC_FS | 506 | #ifdef CONFIG_PROC_FS |
@@ -616,7 +520,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
616 | unsigned long flags; | 520 | unsigned long flags; |
617 | int i = 0; | 521 | int i = 0; |
618 | int num_to_show; | 522 | int num_to_show; |
619 | struct timeval tv; | 523 | struct fasttime_t tv; |
620 | struct fast_timer *t, *nextt; | 524 | struct fast_timer *t, *nextt; |
621 | static char *bigbuf = NULL; | 525 | static char *bigbuf = NULL; |
622 | static unsigned long used; | 526 | static unsigned long used; |
@@ -624,7 +528,8 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
624 | if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) | 528 | if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) |
625 | { | 529 | { |
626 | used = 0; | 530 | used = 0; |
627 | bigbuf[0] = '\0'; | 531 | if (buf) |
532 | buf[0] = '\0'; | ||
628 | return 0; | 533 | return 0; |
629 | } | 534 | } |
630 | 535 | ||
@@ -646,7 +551,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
646 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", | 551 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", |
647 | fast_timer_running ? "yes" : "no"); | 552 | fast_timer_running ? "yes" : "no"); |
648 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", | 553 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", |
649 | (unsigned long)tv.tv_sec, | 554 | (unsigned long)tv.tv_jiff, |
650 | (unsigned long)tv.tv_usec); | 555 | (unsigned long)tv.tv_usec); |
651 | #ifdef FAST_TIMER_SANITY_CHECKS | 556 | #ifdef FAST_TIMER_SANITY_CHECKS |
652 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", | 557 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", |
@@ -696,9 +601,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
696 | "d: %6li us data: 0x%08lX" | 601 | "d: %6li us data: 0x%08lX" |
697 | "\n", | 602 | "\n", |
698 | t->name, | 603 | t->name, |
699 | (unsigned long)t->tv_set.tv_sec, | 604 | (unsigned long)t->tv_set.tv_jiff, |
700 | (unsigned long)t->tv_set.tv_usec, | 605 | (unsigned long)t->tv_set.tv_usec, |
701 | (unsigned long)t->tv_expires.tv_sec, | 606 | (unsigned long)t->tv_expires.tv_jiff, |
702 | (unsigned long)t->tv_expires.tv_usec, | 607 | (unsigned long)t->tv_expires.tv_usec, |
703 | t->delay_us, | 608 | t->delay_us, |
704 | t->data | 609 | t->data |
@@ -718,9 +623,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
718 | "d: %6li us data: 0x%08lX" | 623 | "d: %6li us data: 0x%08lX" |
719 | "\n", | 624 | "\n", |
720 | t->name, | 625 | t->name, |
721 | (unsigned long)t->tv_set.tv_sec, | 626 | (unsigned long)t->tv_set.tv_jiff, |
722 | (unsigned long)t->tv_set.tv_usec, | 627 | (unsigned long)t->tv_set.tv_usec, |
723 | (unsigned long)t->tv_expires.tv_sec, | 628 | (unsigned long)t->tv_expires.tv_jiff, |
724 | (unsigned long)t->tv_expires.tv_usec, | 629 | (unsigned long)t->tv_expires.tv_usec, |
725 | t->delay_us, | 630 | t->delay_us, |
726 | t->data | 631 | t->data |
@@ -738,9 +643,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
738 | "d: %6li us data: 0x%08lX" | 643 | "d: %6li us data: 0x%08lX" |
739 | "\n", | 644 | "\n", |
740 | t->name, | 645 | t->name, |
741 | (unsigned long)t->tv_set.tv_sec, | 646 | (unsigned long)t->tv_set.tv_jiff, |
742 | (unsigned long)t->tv_set.tv_usec, | 647 | (unsigned long)t->tv_set.tv_usec, |
743 | (unsigned long)t->tv_expires.tv_sec, | 648 | (unsigned long)t->tv_expires.tv_jiff, |
744 | (unsigned long)t->tv_expires.tv_usec, | 649 | (unsigned long)t->tv_expires.tv_usec, |
745 | t->delay_us, | 650 | t->delay_us, |
746 | t->data | 651 | t->data |
@@ -761,15 +666,15 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
761 | /* " func: 0x%08lX" */ | 666 | /* " func: 0x%08lX" */ |
762 | "\n", | 667 | "\n", |
763 | t->name, | 668 | t->name, |
764 | (unsigned long)t->tv_set.tv_sec, | 669 | (unsigned long)t->tv_set.tv_jiff, |
765 | (unsigned long)t->tv_set.tv_usec, | 670 | (unsigned long)t->tv_set.tv_usec, |
766 | (unsigned long)t->tv_expires.tv_sec, | 671 | (unsigned long)t->tv_expires.tv_jiff, |
767 | (unsigned long)t->tv_expires.tv_usec, | 672 | (unsigned long)t->tv_expires.tv_usec, |
768 | t->delay_us, | 673 | t->delay_us, |
769 | t->data | 674 | t->data |
770 | /* , t->function */ | 675 | /* , t->function */ |
771 | ); | 676 | ); |
772 | local_irq_disable(); | 677 | local_irq_save(flags); |
773 | if (t->next != nextt) | 678 | if (t->next != nextt) |
774 | { | 679 | { |
775 | printk(KERN_WARNING "timer removed!\n"); | 680 | printk(KERN_WARNING "timer removed!\n"); |
@@ -798,7 +703,7 @@ static volatile int num_test_timeout = 0; | |||
798 | static struct fast_timer tr[10]; | 703 | static struct fast_timer tr[10]; |
799 | static int exp_num[10]; | 704 | static int exp_num[10]; |
800 | 705 | ||
801 | static struct timeval tv_exp[100]; | 706 | static struct fasttime_t tv_exp[100]; |
802 | 707 | ||
803 | static void test_timeout(unsigned long data) | 708 | static void test_timeout(unsigned long data) |
804 | { | 709 | { |
@@ -836,7 +741,7 @@ static void fast_timer_test(void) | |||
836 | int prev_num; | 741 | int prev_num; |
837 | int j; | 742 | int j; |
838 | 743 | ||
839 | struct timeval tv, tv0, tv1, tv2; | 744 | struct fasttime_t tv, tv0, tv1, tv2; |
840 | 745 | ||
841 | printk("fast_timer_test() start\n"); | 746 | printk("fast_timer_test() start\n"); |
842 | do_gettimeofday_fast(&tv); | 747 | do_gettimeofday_fast(&tv); |
@@ -849,7 +754,8 @@ static void fast_timer_test(void) | |||
849 | { | 754 | { |
850 | do_gettimeofday_fast(&tv_exp[j]); | 755 | do_gettimeofday_fast(&tv_exp[j]); |
851 | } | 756 | } |
852 | printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); | 757 | printk(KERN_DEBUG "fast_timer_test() %is %06i\n", |
758 | tv.tv_jiff, tv.tv_usec); | ||
853 | 759 | ||
854 | for (j = 0; j < 1000; j++) | 760 | for (j = 0; j < 1000; j++) |
855 | { | 761 | { |
@@ -858,12 +764,12 @@ static void fast_timer_test(void) | |||
858 | } | 764 | } |
859 | for (j = 0; j < 100; j++) | 765 | for (j = 0; j < 100; j++) |
860 | { | 766 | { |
861 | printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", | 767 | printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n", |
862 | tv_exp[j].tv_sec,tv_exp[j].tv_usec, | 768 | tv_exp[j].tv_jiff, tv_exp[j].tv_usec, |
863 | tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, | 769 | tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec, |
864 | tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, | 770 | tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec, |
865 | tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, | 771 | tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec, |
866 | tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); | 772 | tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec); |
867 | j += 4; | 773 | j += 4; |
868 | } | 774 | } |
869 | do_gettimeofday_fast(&tv0); | 775 | do_gettimeofday_fast(&tv0); |
@@ -895,9 +801,12 @@ static void fast_timer_test(void) | |||
895 | } | 801 | } |
896 | } | 802 | } |
897 | do_gettimeofday_fast(&tv2); | 803 | do_gettimeofday_fast(&tv2); |
898 | printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); | 804 | printk(KERN_DEBUG "Timers started %is %06i\n", |
899 | printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); | 805 | tv0.tv_jiff, tv0.tv_usec); |
900 | printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); | 806 | printk(KERN_DEBUG "Timers started at %is %06i\n", |
807 | tv1.tv_jiff, tv1.tv_usec); | ||
808 | printk(KERN_DEBUG "Timers done %is %06i\n", | ||
809 | tv2.tv_jiff, tv2.tv_usec); | ||
901 | DP(printk("buf0:\n"); | 810 | DP(printk("buf0:\n"); |
902 | printk(buf0); | 811 | printk(buf0); |
903 | printk("buf1:\n"); | 812 | printk("buf1:\n"); |
@@ -919,9 +828,9 @@ static void fast_timer_test(void) | |||
919 | printk("%-10s set: %6is %06ius exp: %6is %06ius " | 828 | printk("%-10s set: %6is %06ius exp: %6is %06ius " |
920 | "data: 0x%08X func: 0x%08X\n", | 829 | "data: 0x%08X func: 0x%08X\n", |
921 | t->name, | 830 | t->name, |
922 | t->tv_set.tv_sec, | 831 | t->tv_set.tv_jiff, |
923 | t->tv_set.tv_usec, | 832 | t->tv_set.tv_usec, |
924 | t->tv_expires.tv_sec, | 833 | t->tv_expires.tv_jiff, |
925 | t->tv_expires.tv_usec, | 834 | t->tv_expires.tv_usec, |
926 | t->data, | 835 | t->data, |
927 | t->function | 836 | t->function |
@@ -929,10 +838,12 @@ static void fast_timer_test(void) | |||
929 | 838 | ||
930 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", | 839 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", |
931 | t->delay_us, | 840 | t->delay_us, |
932 | tv_exp[j].tv_sec, | 841 | tv_exp[j].tv_jiff, |
933 | tv_exp[j].tv_usec, | 842 | tv_exp[j].tv_usec, |
934 | exp_num[j], | 843 | exp_num[j], |
935 | (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); | 844 | (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) * |
845 | 1000000 + tv_exp[j].tv_usec - | ||
846 | t->tv_expires.tv_usec); | ||
936 | } | 847 | } |
937 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | 848 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); |
938 | printk("buf5 after all done:\n"); | 849 | printk("buf5 after all done:\n"); |
@@ -942,7 +853,7 @@ static void fast_timer_test(void) | |||
942 | #endif | 853 | #endif |
943 | 854 | ||
944 | 855 | ||
945 | void fast_timer_init(void) | 856 | int fast_timer_init(void) |
946 | { | 857 | { |
947 | /* For some reason, request_irq() hangs when called froom time_init() */ | 858 | /* For some reason, request_irq() hangs when called froom time_init() */ |
948 | if (!fast_timer_is_init) | 859 | if (!fast_timer_is_init) |
@@ -975,4 +886,6 @@ void fast_timer_init(void) | |||
975 | fast_timer_test(); | 886 | fast_timer_test(); |
976 | #endif | 887 | #endif |
977 | } | 888 | } |
889 | return 0; | ||
978 | } | 890 | } |
891 | __initcall(fast_timer_init); | ||
diff --git a/include/asm-cris/fasttimer.h b/include/asm-cris/fasttimer.h index a3a77132ce32..8f8a8d6c9653 100644 --- a/include/asm-cris/fasttimer.h +++ b/include/asm-cris/fasttimer.h | |||
@@ -1,9 +1,8 @@ | |||
1 | /* $Id: fasttimer.h,v 1.3 2004/05/14 10:19:19 starvik Exp $ | 1 | /* |
2 | * linux/include/asm-cris/fasttimer.h | 2 | * linux/include/asm-cris/fasttimer.h |
3 | * | 3 | * |
4 | * Fast timers for ETRAX100LX | 4 | * Fast timers for ETRAX100LX |
5 | * This may be useful in other OS than Linux so use 2 space indentation... | 5 | * Copyright (C) 2000-2007 Axis Communications AB |
6 | * Copyright (C) 2000, 2002 Axis Communications AB | ||
7 | */ | 6 | */ |
8 | #include <linux/time.h> /* struct timeval */ | 7 | #include <linux/time.h> /* struct timeval */ |
9 | #include <linux/timex.h> | 8 | #include <linux/timex.h> |
@@ -12,11 +11,16 @@ | |||
12 | 11 | ||
13 | typedef void fast_timer_function_type(unsigned long); | 12 | typedef void fast_timer_function_type(unsigned long); |
14 | 13 | ||
14 | struct fasttime_t { | ||
15 | unsigned long tv_jiff; /* jiffies */ | ||
16 | unsigned long tv_usec; /* microseconds */ | ||
17 | }; | ||
18 | |||
15 | struct fast_timer{ /* Close to timer_list */ | 19 | struct fast_timer{ /* Close to timer_list */ |
16 | struct fast_timer *next; | 20 | struct fast_timer *next; |
17 | struct fast_timer *prev; | 21 | struct fast_timer *prev; |
18 | struct timeval tv_set; | 22 | struct fasttime_t tv_set; |
19 | struct timeval tv_expires; | 23 | struct fasttime_t tv_expires; |
20 | unsigned long delay_us; | 24 | unsigned long delay_us; |
21 | fast_timer_function_type *function; | 25 | fast_timer_function_type *function; |
22 | unsigned long data; | 26 | unsigned long data; |
@@ -38,6 +42,6 @@ int del_fast_timer(struct fast_timer * t); | |||
38 | void schedule_usleep(unsigned long us); | 42 | void schedule_usleep(unsigned long us); |
39 | 43 | ||
40 | 44 | ||
41 | void fast_timer_init(void); | 45 | int fast_timer_init(void); |
42 | 46 | ||
43 | #endif | 47 | #endif |