1/* $Id: fasttimer.c,v 1.1.1.1 2007/08/03 18:51:41 Exp $
2 * linux/arch/cris/kernel/fasttimer.c
3 *
4 * Fast timers for ETRAX100/ETRAX100LX
5 * This may be useful in other OS than Linux so use 2 space indentation...
6 *
7 * $Log: fasttimer.c,v $
8 * Revision 1.1.1.1  2007/08/03 18:51:41  rnuti
9 * Importing Linux MIPS Kernel 2.6.22
10 *
11 * Revision 1.9  2005/03/04 08:16:16  starvik
12 * Merge of Linux 2.6.11.
13 *
14 * Revision 1.8  2005/01/05 06:09:29  starvik
15 * cli()/sti() will be obsolete in 2.6.11.
16 *
17 * Revision 1.7  2005/01/03 13:35:46  starvik
18 * Removed obsolete stuff.
19 * Mark fast timer IRQ as not shared.
20 *
21 * Revision 1.6  2004/05/14 10:18:39  starvik
22 * Export fast_timer_list
23 *
24 * Revision 1.5  2004/05/14 07:58:01  starvik
25 * Merge of changes from 2.4
26 *
27 * Revision 1.4  2003/07/04 08:27:41  starvik
28 * Merge of Linux 2.5.74
29 *
30 * Revision 1.3  2002/12/12 08:26:32  starvik
31 * Don't use C-comments inside CVS comments
32 *
33 * Revision 1.2  2002/12/11 15:42:02  starvik
34 * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
35 *
36 * Revision 1.1  2002/11/18 07:58:06  starvik
37 * Fast timers (from Linux 2.4)
38 *
39 * Revision 1.5  2002/10/15 06:21:39  starvik
40 * Added call to init_waitqueue_head
41 *
42 * Revision 1.4  2002/05/28 17:47:59  johana
43 * Added del_fast_timer()
44 *
45 * Revision 1.3  2002/05/28 16:16:07  johana
46 * Handle empty fast_timer_list
47 *
48 * Revision 1.2  2002/05/27 15:38:42  johana
49 * Made it compile without warnings on Linux 2.4.
50 * (includes, wait_queue, PROC_FS and snprintf)
51 *
52 * Revision 1.1  2002/05/27 15:32:25  johana
53 * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
54 *
55 * Revision 1.8  2001/11/27 13:50:40  pkj
56 * Disable interrupts while stopping the timer and while modifying the
57 * list of active timers in timer1_handler() as it may be interrupted
58 * by other interrupts (e.g., the serial interrupt) which may add fast
59 * timers.
60 *
61 * Revision 1.7  2001/11/22 11:50:32  pkj
62 * * Only store information about the last 16 timers.
63 * * proc_fasttimer_read() now uses an allocated buffer, since it
64 *   requires more space than just a page even for only writing the
65 *   last 16 timers. The buffer is only allocated on request, so
66 *   unless /proc/fasttimer is read, it is never allocated.
67 * * Renamed fast_timer_started to fast_timers_started to match
68 *   fast_timers_added and fast_timers_expired.
69 * * Some clean-up.
70 *
71 * Revision 1.6  2000/12/13 14:02:08  johana
72 * Removed volatile for fast_timer_list
73 *
74 * Revision 1.5  2000/12/13 13:55:35  johana
75 * Added DEBUG_LOG, added som cli() and cleanup
76 *
77 * Revision 1.4  2000/12/05 13:48:50  johana
78 * Added range check when writing proc file, modified timer int handling
79 *
80 * Revision 1.3  2000/11/23 10:10:20  johana
81 * More debug/logging possibilities.
82 * Moved GET_JIFFIES_USEC() to timex.h and time.c
83 *
84 * Revision 1.2  2000/11/01 13:41:04  johana
85 * Clean up and bugfixes.
86 * Created new do_gettimeofday_fast() that gets a timeval struct
87 * with time based on jiffies and *R_TIMER0_DATA, uses a table
88 * for fast conversion of timer value to microseconds.
89 * (Much faster the standard do_gettimeofday() and we don't really
90 * wan't to use the true time - we wan't the "uptime" so timers don't screw up
91 * when we change the time.
92 * TODO: Add efficient support for continuous timers as well.
93 *
94 * Revision 1.1  2000/10/26 15:49:16  johana
95 * Added fasttimer, highresolution timers.
96 *
97 * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
98 */
99
100#include <linux/errno.h>
101#include <linux/sched.h>
102#include <linux/kernel.h>
103#include <linux/param.h>
104#include <linux/string.h>
105#include <linux/mm.h>
106#include <linux/vmalloc.h>
107#include <linux/interrupt.h>
108#include <linux/time.h>
109#include <linux/delay.h>
110
111#include <asm/segment.h>
112#include <asm/io.h>
113#include <asm/irq.h>
114#include <asm/delay.h>
115#include <asm/rtc.h>
116
117
118#include <asm/arch/svinto.h>
119#include <asm/fasttimer.h>
120#include <linux/proc_fs.h>
121
122
123#define DEBUG_LOG_INCLUDED
124#define FAST_TIMER_LOG
125//#define FAST_TIMER_TEST
126
127#define FAST_TIMER_SANITY_CHECKS
128
129#ifdef FAST_TIMER_SANITY_CHECKS
130#define SANITYCHECK(x) x
131static int sanity_failed = 0;
132#else
133#define SANITYCHECK(x)
134#endif
135
136#define D1(x)
137#define D2(x)
138#define DP(x)
139
140#define __INLINE__ inline
141
142static int fast_timer_running = 0;
143static int fast_timers_added = 0;
144static int fast_timers_started = 0;
145static int fast_timers_expired = 0;
146static int fast_timers_deleted = 0;
147static int fast_timer_is_init = 0;
148static int fast_timer_ints = 0;
149
150struct fast_timer *fast_timer_list = NULL;
151
152#ifdef DEBUG_LOG_INCLUDED
153#define DEBUG_LOG_MAX 128
154static const char * debug_log_string[DEBUG_LOG_MAX];
155static unsigned long debug_log_value[DEBUG_LOG_MAX];
156static int debug_log_cnt = 0;
157static int debug_log_cnt_wrapped = 0;
158
159#define DEBUG_LOG(string, value) \
160{ \
161  unsigned long log_flags; \
162  local_irq_save(log_flags); \
163  debug_log_string[debug_log_cnt] = (string); \
164  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
165  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
166  { \
167    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
168    debug_log_cnt_wrapped = 1; \
169  } \
170  local_irq_restore(log_flags); \
171}
172#else
173#define DEBUG_LOG(string, value)
174#endif
175
176
177/* The frequencies for index = clkselx number in R_TIMER_CTRL */
178#define NUM_TIMER_FREQ 15
179#define MAX_USABLE_TIMER_FREQ 7
180#define MAX_DELAY_US  853333L
181const unsigned long timer_freq_100[NUM_TIMER_FREQ] =
182{
183  3,   /* 0 3333 - 853333 us */
184  6,   /* 1 1666 - 426666 us */
185  12,  /* 2  833 - 213333 us */
186  24,  /* 3  416 - 106666 us */
187  48,  /* 4  208 -  53333 us */
188  96,  /* 5  104 -  26666 us */
189  192, /* 6   52 -  13333 us */
190  384, /* 7   26 -   6666 us */
191  576,
192  1152,
193  2304,
194  4608,
195  9216,
196  18432,
197  62500,
198  /* 15 = cascade */
199};
200#define NUM_TIMER_STATS 16
201#ifdef FAST_TIMER_LOG
202struct fast_timer timer_added_log[NUM_TIMER_STATS];
203struct fast_timer timer_started_log[NUM_TIMER_STATS];
204struct fast_timer timer_expired_log[NUM_TIMER_STATS];
205#endif
206
207int timer_div_settings[NUM_TIMER_STATS];
208int timer_freq_settings[NUM_TIMER_STATS];
209int timer_delay_settings[NUM_TIMER_STATS];
210
211/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
212void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
213{
214  unsigned long sec = jiffies;
215  unsigned long usec = GET_JIFFIES_USEC();
216
217  usec += (sec % HZ) * (1000000 / HZ);
218  sec = sec / HZ;
219
220  if (usec > 1000000)
221  {
222    usec -= 1000000;
223    sec++;
224  }
225  tv->tv_sec = sec;
226  tv->tv_usec = usec;
227}
228
229int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
230{
231  if (t0->tv_sec < t1->tv_sec)
232  {
233    return -1;
234  }
235  else if (t0->tv_sec > t1->tv_sec)
236  {
237    return 1;
238  }
239  if (t0->tv_usec < t1->tv_usec)
240  {
241    return -1;
242  }
243  else if (t0->tv_usec > t1->tv_usec)
244  {
245    return 1;
246  }
247  return 0;
248}
249
250void __INLINE__ start_timer1(unsigned long delay_us)
251{
252  int freq_index = 0; /* This is the lowest resolution */
253  unsigned long upper_limit = MAX_DELAY_US;
254
255  unsigned long div;
256  /* Start/Restart the timer to the new shorter value */
257  /* t = 1/freq = 1/19200 = 53us
258   * T=div*t,  div = T/t = delay_us*freq/1000000
259   */
260  while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)
261  {
262    freq_index++;
263    upper_limit >>= 1; /* Divide by 2 using shift */
264  }
265  if (freq_index > 0)
266  {
267    freq_index--;
268  }
269  div = delay_us * timer_freq_100[freq_index]/10000;
270  if (div < 2)
271  {
272    /* Maybe increase timer freq? */
273    div = 2;
274  }
275  if (div > 255)
276  {
277    div = 0; /* This means 256, the max the timer takes */
278    /* If a longer timeout than the timer can handle is used,
279     * then we must restart it when it goes off.
280     */
281  }
282
283  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;
284  timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
285  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
286
287  D1(printk("start_timer1 : %d us freq: %i div: %i\n",
288            delay_us, freq_index, div));
289  /* Clear timer1 irq */
290  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
291
292  /* Set timer values */
293  *R_TIMER_CTRL = r_timer_ctrl_shadow =
294    (r_timer_ctrl_shadow &
295     ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
296     ~IO_MASK(R_TIMER_CTRL, tm1) &
297     ~IO_MASK(R_TIMER_CTRL, clksel1)) |
298    IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |
299    IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
300    IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */
301
302  /* Ack interrupt */
303  *R_TIMER_CTRL =  r_timer_ctrl_shadow |
304    IO_STATE(R_TIMER_CTRL, i1, clr);
305
306  /* Start timer */
307  *R_TIMER_CTRL = r_timer_ctrl_shadow =
308    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
309    IO_STATE(R_TIMER_CTRL, tm1, run);
310
311  /* Enable timer1 irq */
312  *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
313  fast_timers_started++;
314  fast_timer_running = 1;
315}
316
317/* In version 1.4 this function takes 27 - 50 us */
318void start_one_shot_timer(struct fast_timer *t,
319                          fast_timer_function_type *function,
320                          unsigned long data,
321                          unsigned long delay_us,
322                          const char *name)
323{
324  unsigned long flags;
325  struct fast_timer *tmp;
326
327  D1(printk("sft %s %d us\n", name, delay_us));
328
329  local_irq_save(flags);
330
331  do_gettimeofday_fast(&t->tv_set);
332  tmp = fast_timer_list;
333
334  SANITYCHECK({ /* Check so this is not in the list already... */
335    while (tmp != NULL)
336    {
337      if (tmp == t)
338      {
339        printk(KERN_WARNING
340               "timer name: %s data: 0x%08lX already in list!\n", name, data);
341        sanity_failed++;
342        return;
343      }
344      else
345      {
346        tmp = tmp->next;
347      }
348    }
349    tmp = fast_timer_list;
350  });
351
352  t->delay_us = delay_us;
353  t->function = function;
354  t->data = data;
355  t->name = name;
356
357  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
358  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
359  if (t->tv_expires.tv_usec > 1000000)
360  {
361    t->tv_expires.tv_usec -= 1000000;
362    t->tv_expires.tv_sec++;
363  }
364#ifdef FAST_TIMER_LOG
365  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
366#endif
367  fast_timers_added++;
368
369  /* Check if this should timeout before anything else */
370  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
371  {
372    /* Put first in list and modify the timer value */
373    t->prev = NULL;
374    t->next = fast_timer_list;
375    if (fast_timer_list)
376    {
377      fast_timer_list->prev = t;
378    }
379    fast_timer_list = t;
380#ifdef FAST_TIMER_LOG
381    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
382#endif
383    start_timer1(delay_us);
384  } else {
385    /* Put in correct place in list */
386    while (tmp->next &&
387           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
388    {
389      tmp = tmp->next;
390    }
391    /* Insert t after tmp */
392    t->prev = tmp;
393    t->next = tmp->next;
394    if (tmp->next)
395    {
396      tmp->next->prev = t;
397    }
398    tmp->next = t;
399  }
400
401  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
402
403  local_irq_restore(flags);
404} /* start_one_shot_timer */
405
406static inline int fast_timer_pending (const struct fast_timer * t)
407{
408  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
409}
410
411static inline int detach_fast_timer (struct fast_timer *t)
412{
413  struct fast_timer *next, *prev;
414  if (!fast_timer_pending(t))
415    return 0;
416  next = t->next;
417  prev = t->prev;
418  if (next)
419    next->prev = prev;
420  if (prev)
421    prev->next = next;
422  else
423    fast_timer_list = next;
424  fast_timers_deleted++;
425  return 1;
426}
427
428int del_fast_timer(struct fast_timer * t)
429{
430  unsigned long flags;
431  int ret;
432
433  local_irq_save(flags);
434  ret = detach_fast_timer(t);
435  t->next = t->prev = NULL;
436  local_irq_restore(flags);
437  return ret;
438} /* del_fast_timer */
439
440
441/* Interrupt routines or functions called in interrupt context */
442
443/* Timer 1 interrupt handler */
444
445static irqreturn_t
446timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
447{
448  struct fast_timer *t;
449  unsigned long flags;
450
451  local_irq_save(flags);
452
453  /* Clear timer1 irq */
454  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
455
456  /* First stop timer, then ack interrupt */
457  /* Stop timer */
458  *R_TIMER_CTRL = r_timer_ctrl_shadow =
459    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
460    IO_STATE(R_TIMER_CTRL, tm1, stop_ld);
461
462  /* Ack interrupt */
463  *R_TIMER_CTRL =  r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);
464
465  fast_timer_running = 0;
466  fast_timer_ints++;
467
468  local_irq_restore(flags);
469
470  t = fast_timer_list;
471  while (t)
472  {
473    struct timeval tv;
474
475    /* Has it really expired? */
476    do_gettimeofday_fast(&tv);
477    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
478
479    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
480    {
481      /* Yes it has expired */
482#ifdef FAST_TIMER_LOG
483      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
484#endif
485      fast_timers_expired++;
486
487      /* Remove this timer before call, since it may reuse the timer */
488      local_irq_save(flags);
489      if (t->prev)
490      {
491        t->prev->next = t->next;
492      }
493      else
494      {
495        fast_timer_list = t->next;
496      }
497      if (t->next)
498      {
499        t->next->prev = t->prev;
500      }
501      t->prev = NULL;
502      t->next = NULL;
503      local_irq_restore(flags);
504
505      if (t->function != NULL)
506      {
507        t->function(t->data);
508      }
509      else
510      {
511        DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
512      }
513    }
514    else
515    {
516      /* Timer is to early, let's set it again using the normal routines */
517      D1(printk(".\n"));
518    }
519
520    local_irq_save(flags);
521    if ((t = fast_timer_list) != NULL)
522    {
523      /* Start next timer.. */
524      long us;
525      struct timeval tv;
526
527      do_gettimeofday_fast(&tv);
528      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
529            t->tv_expires.tv_usec - tv.tv_usec);
530      if (us > 0)
531      {
532        if (!fast_timer_running)
533        {
534#ifdef FAST_TIMER_LOG
535          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
536#endif
537          start_timer1(us);
538        }
539        local_irq_restore(flags);
540        break;
541      }
542      else
543      {
544        /* Timer already expired, let's handle it better late than never.
545         * The normal loop handles it
546         */
547        D1(printk("e! %d\n", us));
548      }
549    }
550    local_irq_restore(flags);
551  }
552
553  if (!t)
554  {
555    D1(printk("t1 stop!\n"));
556  }
557
558  return IRQ_HANDLED;
559}
560
561static void wake_up_func(unsigned long data)
562{
563#ifdef DECLARE_WAITQUEUE
564  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
565#else
566  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
567#endif
568  wake_up(sleep_wait_p);
569}
570
571
572/* Useful API */
573
574void schedule_usleep(unsigned long us)
575{
576  struct fast_timer t;
577#ifdef DECLARE_WAITQUEUE
578  wait_queue_head_t sleep_wait;
579  init_waitqueue_head(&sleep_wait);
580  {
581  DECLARE_WAITQUEUE(wait, current);
582#else
583  struct wait_queue *sleep_wait = NULL;
584  struct wait_queue wait = { current, NULL };
585#endif
586
587  D1(printk("schedule_usleep(%d)\n", us));
588  add_wait_queue(&sleep_wait, &wait);
589  set_current_state(TASK_INTERRUPTIBLE);
590  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
591                       "usleep");
592  schedule();
593  set_current_state(TASK_RUNNING);
594  remove_wait_queue(&sleep_wait, &wait);
595  D1(printk("done schedule_usleep(%d)\n", us));
596#ifdef DECLARE_WAITQUEUE
597  }
598#endif
599}
600
601#ifdef CONFIG_PROC_FS
602static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
603                       ,int *eof, void *data_unused);
604static struct proc_dir_entry *fasttimer_proc_entry;
605#endif /* CONFIG_PROC_FS */
606
607#ifdef CONFIG_PROC_FS
608
609/* This value is very much based on testing */
610#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
611
612static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
613                       ,int *eof, void *data_unused)
614{
615  unsigned long flags;
616  int i = 0;
617  int num_to_show;
618  struct timeval tv;
619  struct fast_timer *t, *nextt;
620  static char *bigbuf = NULL;
621  static unsigned long used;
622
623  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
624  {
625    used = 0;
626    bigbuf[0] = '\0';
627    return 0;
628  }
629
630  if (!offset || !used)
631  {
632    do_gettimeofday_fast(&tv);
633
634    used = 0;
635    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
636                    fast_timers_added);
637    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
638                    fast_timers_started);
639    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
640                    fast_timer_ints);
641    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
642                    fast_timers_expired);
643    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
644                    fast_timers_deleted);
645    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
646                    fast_timer_running ? "yes" : "no");
647    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
648                    (unsigned long)tv.tv_sec,
649                    (unsigned long)tv.tv_usec);
650#ifdef FAST_TIMER_SANITY_CHECKS
651    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
652                    sanity_failed);
653#endif
654    used += sprintf(bigbuf + used, "\n");
655
656#ifdef DEBUG_LOG_INCLUDED
657    {
658      int end_i = debug_log_cnt;
659      i = 0;
660
661      if (debug_log_cnt_wrapped)
662      {
663        i = debug_log_cnt;
664      }
665
666      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
667             used+100 < BIG_BUF_SIZE)
668      {
669        used += sprintf(bigbuf + used, debug_log_string[i],
670                        debug_log_value[i]);
671        i = (i+1) % DEBUG_LOG_MAX;
672      }
673    }
674    used += sprintf(bigbuf + used, "\n");
675#endif
676
677    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
678                   NUM_TIMER_STATS);
679    used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
680    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
681    {
682      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
683
684      used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
685                      "\n",
686                      timer_div_settings[cur],
687                      timer_freq_settings[cur],
688                      timer_delay_settings[cur]
689                      );
690#ifdef FAST_TIMER_LOG
691      t = &timer_started_log[cur];
692      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
693                      "d: %6li us data: 0x%08lX"
694                      "\n",
695                      t->name,
696                      (unsigned long)t->tv_set.tv_sec,
697                      (unsigned long)t->tv_set.tv_usec,
698                      (unsigned long)t->tv_expires.tv_sec,
699                      (unsigned long)t->tv_expires.tv_usec,
700                      t->delay_us,
701                      t->data
702                      );
703#endif
704    }
705    used += sprintf(bigbuf + used, "\n");
706
707#ifdef FAST_TIMER_LOG
708    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
709                   NUM_TIMER_STATS);
710    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
711    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
712    {
713      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
714      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
715                      "d: %6li us data: 0x%08lX"
716                      "\n",
717                      t->name,
718                      (unsigned long)t->tv_set.tv_sec,
719                      (unsigned long)t->tv_set.tv_usec,
720                      (unsigned long)t->tv_expires.tv_sec,
721                      (unsigned long)t->tv_expires.tv_usec,
722                      t->delay_us,
723                      t->data
724                      );
725    }
726    used += sprintf(bigbuf + used, "\n");
727
728    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
729                   NUM_TIMER_STATS);
730    used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
731    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
732    {
733      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
734      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
735                      "d: %6li us data: 0x%08lX"
736                      "\n",
737                      t->name,
738                      (unsigned long)t->tv_set.tv_sec,
739                      (unsigned long)t->tv_set.tv_usec,
740                      (unsigned long)t->tv_expires.tv_sec,
741                      (unsigned long)t->tv_expires.tv_usec,
742                      t->delay_us,
743                      t->data
744                      );
745    }
746    used += sprintf(bigbuf + used, "\n");
747#endif
748
749    used += sprintf(bigbuf + used, "Active timers:\n");
750    local_irq_save(flags);
751    t = fast_timer_list;
752    while (t != NULL && (used+100 < BIG_BUF_SIZE))
753    {
754      nextt = t->next;
755      local_irq_restore(flags);
756      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
757                      "d: %6li us data: 0x%08lX"
758/*                      " func: 0x%08lX" */
759                      "\n",
760                      t->name,
761                      (unsigned long)t->tv_set.tv_sec,
762                      (unsigned long)t->tv_set.tv_usec,
763                      (unsigned long)t->tv_expires.tv_sec,
764                      (unsigned long)t->tv_expires.tv_usec,
765                      t->delay_us,
766                      t->data
767/*                      , t->function */
768                      );
769      local_irq_disable();
770      if (t->next != nextt)
771      {
772        printk(KERN_WARNING "timer removed!\n");
773      }
774      t = nextt;
775    }
776    local_irq_restore(flags);
777  }
778
779  if (used - offset < len)
780  {
781    len = used - offset;
782  }
783
784  memcpy(buf, bigbuf + offset, len);
785  *start = buf;
786  *eof = 1;
787
788  return len;
789}
790#endif /* PROC_FS */
791
792#ifdef FAST_TIMER_TEST
793static volatile unsigned long i = 0;
794static volatile int num_test_timeout = 0;
795static struct fast_timer tr[10];
796static int exp_num[10];
797
798static struct timeval tv_exp[100];
799
800static void test_timeout(unsigned long data)
801{
802  do_gettimeofday_fast(&tv_exp[data]);
803  exp_num[data] = num_test_timeout;
804
805  num_test_timeout++;
806}
807
808static void test_timeout1(unsigned long data)
809{
810  do_gettimeofday_fast(&tv_exp[data]);
811  exp_num[data] = num_test_timeout;
812  if (data < 7)
813  {
814    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
815    i++;
816  }
817  num_test_timeout++;
818}
819
820DP(
821static char buf0[2000];
822static char buf1[2000];
823static char buf2[2000];
824static char buf3[2000];
825static char buf4[2000];
826);
827
828static char buf5[6000];
829static int j_u[1000];
830
831static void fast_timer_test(void)
832{
833  int prev_num;
834  int j;
835
836  struct timeval tv, tv0, tv1, tv2;
837
838  printk("fast_timer_test() start\n");
839  do_gettimeofday_fast(&tv);
840
841  for (j = 0; j < 1000; j++)
842  {
843    j_u[j] = GET_JIFFIES_USEC();
844  }
845  for (j = 0; j < 100; j++)
846  {
847    do_gettimeofday_fast(&tv_exp[j]);
848  }
849  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
850
851  for (j = 0; j < 1000; j++)
852  {
853    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
854    j += 4;
855  }
856  for (j = 0; j < 100; j++)
857  {
858    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
859           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
860           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
861           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
862           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
863           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
864    j += 4;
865  }
866  do_gettimeofday_fast(&tv0);
867  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
868  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
869  i++;
870  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
871  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
872  i++;
873  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
874  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
875  i++;
876  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
877  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
878  i++;
879  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
880  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
881  i++;
882  do_gettimeofday_fast(&tv1);
883
884  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
885
886  prev_num = num_test_timeout;
887  while (num_test_timeout < i)
888  {
889    if (num_test_timeout != prev_num)
890    {
891      prev_num = num_test_timeout;
892    }
893  }
894  do_gettimeofday_fast(&tv2);
895  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
896  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
897  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
898  DP(printk("buf0:\n");
899     printk(buf0);
900     printk("buf1:\n");
901     printk(buf1);
902     printk("buf2:\n");
903     printk(buf2);
904     printk("buf3:\n");
905     printk(buf3);
906     printk("buf4:\n");
907     printk(buf4);
908  );
909  printk("buf5:\n");
910  printk(buf5);
911
912  printk("timers set:\n");
913  for(j = 0; j<i; j++)
914  {
915    struct fast_timer *t = &tr[j];
916    printk("%-10s set: %6is %06ius exp: %6is %06ius "
917           "data: 0x%08X func: 0x%08X\n",
918           t->name,
919           t->tv_set.tv_sec,
920           t->tv_set.tv_usec,
921           t->tv_expires.tv_sec,
922           t->tv_expires.tv_usec,
923           t->data,
924           t->function
925           );
926
927    printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
928           t->delay_us,
929           tv_exp[j].tv_sec,
930           tv_exp[j].tv_usec,
931           exp_num[j],
932           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
933  }
934  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
935  printk("buf5 after all done:\n");
936  printk(buf5);
937  printk("fast_timer_test() done\n");
938}
939#endif
940
941
942void fast_timer_init(void)
943{
944  /* For some reason, request_irq() hangs when called froom time_init() */
945  if (!fast_timer_is_init)
946  {
947
948    printk(KERN_INFO "fast_timer_init()\n");
949
950#ifdef CONFIG_PROC_FS
951   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
952     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
953#endif /* PROC_FS */
954    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0,
955                   "fast timer int", NULL))
956    {
957      printk("err: timer1 irq\n");
958    }
959    fast_timer_is_init = 1;
960#ifdef FAST_TIMER_TEST
961    printk("do test\n");
962    fast_timer_test();
963#endif
964  }
965}
966