• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux/arch/cris/kernel/fasttimer.c
3  *
4  * Fast timers for ETRAX FS
5  *
6  * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden
7  */
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 
21 #include <hwregs/reg_map.h>
22 #include <hwregs/reg_rdwr.h>
23 #include <hwregs/timer_defs.h>
24 #include <asm/fasttimer.h>
25 #include <linux/proc_fs.h>
26 
27 /*
28  * timer0 is running at 100MHz and generating jiffies timer ticks
29  * at 100 or 1000 HZ.
30  * fasttimer gives an API that gives timers that expire "between" the jiffies
31  * giving microsecond resolution (10 ns).
32  * fasttimer uses reg_timer_rw_trig register to get interrupt when
33  * r_time reaches a certain value.
34  */
35 
36 
37 #define DEBUG_LOG_INCLUDED
38 #define FAST_TIMER_LOG
39 /* #define FAST_TIMER_TEST */
40 
41 #define FAST_TIMER_SANITY_CHECKS
42 
43 #ifdef FAST_TIMER_SANITY_CHECKS
44 static int sanity_failed;
45 #endif
46 
47 #define D1(x)
48 #define D2(x)
49 #define DP(x)
50 
51 static unsigned int fast_timer_running;
52 static unsigned int fast_timers_added;
53 static unsigned int fast_timers_started;
54 static unsigned int fast_timers_expired;
55 static unsigned int fast_timers_deleted;
56 static unsigned int fast_timer_is_init;
57 static unsigned int fast_timer_ints;
58 
59 struct fast_timer *fast_timer_list = NULL;
60 
61 #ifdef DEBUG_LOG_INCLUDED
62 #define DEBUG_LOG_MAX 128
63 static const char * debug_log_string[DEBUG_LOG_MAX];
64 static unsigned long debug_log_value[DEBUG_LOG_MAX];
65 static unsigned int debug_log_cnt;
66 static unsigned int debug_log_cnt_wrapped;
67 
68 #define DEBUG_LOG(string, value) \
69 { \
70   unsigned long log_flags; \
71   local_irq_save(log_flags); \
72   debug_log_string[debug_log_cnt] = (string); \
73   debug_log_value[debug_log_cnt] = (unsigned long)(value); \
74   if (++debug_log_cnt >= DEBUG_LOG_MAX) \
75   { \
76     debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
77     debug_log_cnt_wrapped = 1; \
78   } \
79   local_irq_restore(log_flags); \
80 }
81 #else
82 #define DEBUG_LOG(string, value)
83 #endif
84 
85 
86 #define NUM_TIMER_STATS 16
87 #ifdef FAST_TIMER_LOG
88 struct fast_timer timer_added_log[NUM_TIMER_STATS];
89 struct fast_timer timer_started_log[NUM_TIMER_STATS];
90 struct fast_timer timer_expired_log[NUM_TIMER_STATS];
91 #endif
92 
93 int timer_div_settings[NUM_TIMER_STATS];
94 int timer_delay_settings[NUM_TIMER_STATS];
95 
96 struct work_struct fast_work;
97 
98 static void
99 timer_trig_handler(struct work_struct *work);
100 
101 
102 
103 /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
do_gettimeofday_fast(struct fasttime_t * tv)104 inline void do_gettimeofday_fast(struct fasttime_t *tv)
105 {
106 	tv->tv_jiff = jiffies;
107 	tv->tv_usec = GET_JIFFIES_USEC();
108 }
109 
fasttime_cmp(struct fasttime_t * t0,struct fasttime_t * t1)110 inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)
111 {
112 	/* Compare jiffies. Takes care of wrapping */
113 	if (time_before(t0->tv_jiff, t1->tv_jiff))
114 		return -1;
115 	else if (time_after(t0->tv_jiff, t1->tv_jiff))
116 		return 1;
117 
118 	/* Compare us */
119 	if (t0->tv_usec < t1->tv_usec)
120 		return -1;
121 	else if (t0->tv_usec > t1->tv_usec)
122 		return 1;
123 	return 0;
124 }
125 
126 /* Called with ints off */
start_timer_trig(unsigned long delay_us)127 inline void start_timer_trig(unsigned long delay_us)
128 {
129   reg_timer_rw_ack_intr ack_intr = { 0 };
130   reg_timer_rw_intr_mask intr_mask;
131   reg_timer_rw_trig trig;
132   reg_timer_rw_trig_cfg trig_cfg = { 0 };
133 	reg_timer_r_time r_time0;
134 	reg_timer_r_time r_time1;
135 	unsigned char trig_wrap;
136 	unsigned char time_wrap;
137 
138 	r_time0 = REG_RD(timer, regi_timer0, r_time);
139 
140   D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
141             delay_us, freq_index, div));
142   /* Clear trig irq */
143 	intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
144   intr_mask.trig = 0;
145 	REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
146 
147 	/* Set timer values and check if trigger wraps. */
148 	/* r_time is 100MHz (10 ns resolution) */
149 	trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;
150 
151   timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
152   timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
153 
154   /* Ack interrupt */
155   ack_intr.trig = 1;
156 	REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
157 
158   /* Start timer */
159 	REG_WR(timer, regi_timer0, rw_trig, trig);
160   trig_cfg.tmr = regk_timer_time;
161 	REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
162 
163   /* Check if we have already passed the trig time */
164 	r_time1 = REG_RD(timer, regi_timer0, r_time);
165 	time_wrap = r_time1 < r_time0;
166 
167 	if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {
168     /* No, Enable trig irq */
169 		intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
170     intr_mask.trig = 1;
171 		REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
172     fast_timers_started++;
173     fast_timer_running = 1;
174 	} else {
175     /* We have passed the time, disable trig point, ack intr */
176     trig_cfg.tmr = regk_timer_off;
177 		REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
178 		REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
179 		/* call the int routine */
180 		INIT_WORK(&fast_work, timer_trig_handler);
181 		schedule_work(&fast_work);
182   }
183 
184 }
185 
186 /* In version 1.4 this function takes 27 - 50 us */
start_one_shot_timer(struct fast_timer * t,fast_timer_function_type * function,unsigned long data,unsigned long delay_us,const char * name)187 void start_one_shot_timer(struct fast_timer *t,
188                           fast_timer_function_type *function,
189                           unsigned long data,
190                           unsigned long delay_us,
191                           const char *name)
192 {
193   unsigned long flags;
194   struct fast_timer *tmp;
195 
196   D1(printk("sft %s %d us\n", name, delay_us));
197 
198   local_irq_save(flags);
199 
200   do_gettimeofday_fast(&t->tv_set);
201   tmp = fast_timer_list;
202 
203 #ifdef FAST_TIMER_SANITY_CHECKS
204 	/* Check so this is not in the list already... */
205 	while (tmp != NULL) {
206 		if (tmp == t) {
207 			printk(KERN_DEBUG
208 				"timer name: %s data: 0x%08lX already "
209 				"in list!\n", name, data);
210 			sanity_failed++;
211 			goto done;
212 		} else
213 			tmp = tmp->next;
214 	}
215 	tmp = fast_timer_list;
216 #endif
217 
218   t->delay_us = delay_us;
219   t->function = function;
220   t->data = data;
221   t->name = name;
222 
223   t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
224 	t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
225 	if (t->tv_expires.tv_usec > 1000000) {
226     t->tv_expires.tv_usec -= 1000000;
227 		t->tv_expires.tv_jiff += HZ;
228   }
229 #ifdef FAST_TIMER_LOG
230   timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
231 #endif
232   fast_timers_added++;
233 
234   /* Check if this should timeout before anything else */
235   if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) {
236     /* Put first in list and modify the timer value */
237     t->prev = NULL;
238     t->next = fast_timer_list;
239     if (fast_timer_list)
240       fast_timer_list->prev = t;
241     fast_timer_list = t;
242 #ifdef FAST_TIMER_LOG
243     timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
244 #endif
245     start_timer_trig(delay_us);
246   } else {
247     /* Put in correct place in list */
248     while (tmp->next &&
249         fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
250       tmp = tmp->next;
251     /* Insert t after tmp */
252     t->prev = tmp;
253     t->next = tmp->next;
254     if (tmp->next)
255     {
256       tmp->next->prev = t;
257     }
258     tmp->next = t;
259   }
260 
261   D2(printk("start_one_shot_timer: %d us done\n", delay_us));
262 
263 done:
264   local_irq_restore(flags);
265 } /* start_one_shot_timer */
266 
fast_timer_pending(const struct fast_timer * t)267 static inline int fast_timer_pending (const struct fast_timer * t)
268 {
269   return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
270 }
271 
detach_fast_timer(struct fast_timer * t)272 static inline int detach_fast_timer (struct fast_timer *t)
273 {
274   struct fast_timer *next, *prev;
275   if (!fast_timer_pending(t))
276     return 0;
277   next = t->next;
278   prev = t->prev;
279   if (next)
280     next->prev = prev;
281   if (prev)
282     prev->next = next;
283   else
284     fast_timer_list = next;
285   fast_timers_deleted++;
286   return 1;
287 }
288 
del_fast_timer(struct fast_timer * t)289 int del_fast_timer(struct fast_timer * t)
290 {
291   unsigned long flags;
292   int ret;
293 
294   local_irq_save(flags);
295   ret = detach_fast_timer(t);
296   t->next = t->prev = NULL;
297   local_irq_restore(flags);
298   return ret;
299 } /* del_fast_timer */
300 
301 
302 /* Interrupt routines or functions called in interrupt context */
303 
304 /* Timer interrupt handler for trig interrupts */
305 
306 static irqreturn_t
timer_trig_interrupt(int irq,void * dev_id)307 timer_trig_interrupt(int irq, void *dev_id)
308 {
309   reg_timer_r_masked_intr masked_intr;
310   /* Check if the timer interrupt is for us (a trig int) */
311 	masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);
312   if (!masked_intr.trig)
313     return IRQ_NONE;
314 	timer_trig_handler(NULL);
315   return IRQ_HANDLED;
316 }
317 
timer_trig_handler(struct work_struct * work)318 static void timer_trig_handler(struct work_struct *work)
319 {
320   reg_timer_rw_ack_intr ack_intr = { 0 };
321   reg_timer_rw_intr_mask intr_mask;
322   reg_timer_rw_trig_cfg trig_cfg = { 0 };
323   struct fast_timer *t;
324   unsigned long flags;
325 
326 	/* We keep interrupts disabled not only when we modify the
327 	 * fast timer list, but any time we hold a reference to a
328 	 * timer in the list, since del_fast_timer may be called
329 	 * from (another) interrupt context.  Thus, the only time
330 	 * when interrupts are enabled is when calling the timer
331 	 * callback function.
332 	 */
333   local_irq_save(flags);
334 
335   /* Clear timer trig interrupt */
336 	intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
337   intr_mask.trig = 0;
338   REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
339 
340   /* First stop timer, then ack interrupt */
341   /* Stop timer */
342   trig_cfg.tmr = regk_timer_off;
343 	REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
344 
345   /* Ack interrupt */
346   ack_intr.trig = 1;
347 	REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
348 
349   fast_timer_running = 0;
350   fast_timer_ints++;
351 
352 	fast_timer_function_type *f;
353 	unsigned long d;
354 
355   t = fast_timer_list;
356 	while (t) {
357 		struct fasttime_t tv;
358 
359     /* Has it really expired? */
360     do_gettimeofday_fast(&tv);
361 		D1(printk(KERN_DEBUG
362 			"t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));
363 
364 		if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {
365       /* Yes it has expired */
366 #ifdef FAST_TIMER_LOG
367       timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
368 #endif
369       fast_timers_expired++;
370 
371       /* Remove this timer before call, since it may reuse the timer */
372       if (t->prev)
373         t->prev->next = t->next;
374       else
375         fast_timer_list = t->next;
376       if (t->next)
377         t->next->prev = t->prev;
378       t->prev = NULL;
379       t->next = NULL;
380 
381 			/* Save function callback data before enabling
382 			 * interrupts, since the timer may be removed and we
383 			 * don't know how it was allocated (e.g. ->function
384 			 * and ->data may become overwritten after deletion
385 			 * if the timer was stack-allocated).
386 			 */
387 			f = t->function;
388 			d = t->data;
389 
390 			if (f != NULL) {
391 				/* Run the callback function with interrupts
392 				 * enabled. */
393 				local_irq_restore(flags);
394 				f(d);
395 				local_irq_save(flags);
396 			} else
397         DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
398 		} else {
399       /* Timer is to early, let's set it again using the normal routines */
400       D1(printk(".\n"));
401     }
402 
403 		t = fast_timer_list;
404 		if (t != NULL) {
405       /* Start next timer.. */
406 			long us = 0;
407 			struct fasttime_t tv;
408 
409       do_gettimeofday_fast(&tv);
410 
411 			/* time_after_eq takes care of wrapping */
412 			if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
413 				us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
414 					1000000 / HZ + t->tv_expires.tv_usec -
415 					tv.tv_usec);
416 
417 			if (us > 0) {
418 				if (!fast_timer_running) {
419 #ifdef FAST_TIMER_LOG
420           timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
421 #endif
422           start_timer_trig(us);
423         }
424         break;
425 			} else {
426         /* Timer already expired, let's handle it better late than never.
427          * The normal loop handles it
428          */
429         D1(printk("e! %d\n", us));
430       }
431     }
432   }
433 
434 	local_irq_restore(flags);
435 
436 	if (!t)
437     D1(printk("ttrig stop!\n"));
438 }
439 
wake_up_func(unsigned long data)440 static void wake_up_func(unsigned long data)
441 {
442   wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
443   wake_up(sleep_wait_p);
444 }
445 
446 
447 /* Useful API */
448 
schedule_usleep(unsigned long us)449 void schedule_usleep(unsigned long us)
450 {
451   struct fast_timer t;
452   wait_queue_head_t sleep_wait;
453   init_waitqueue_head(&sleep_wait);
454 
455   D1(printk("schedule_usleep(%d)\n", us));
456   start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
457                        "usleep");
458 	/* Uninterruptible sleep on the fast timer. (The condition is
459 	 * somewhat redundant since the timer is what wakes us up.) */
460 	wait_event(sleep_wait, !fast_timer_pending(&t));
461 
462   D1(printk("done schedule_usleep(%d)\n", us));
463 }
464 
465 #ifdef CONFIG_PROC_FS
466 static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
467                        ,int *eof, void *data_unused);
468 static struct proc_dir_entry *fasttimer_proc_entry;
469 #endif /* CONFIG_PROC_FS */
470 
471 #ifdef CONFIG_PROC_FS
472 
473 /* This value is very much based on testing */
474 #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
475 
proc_fasttimer_read(char * buf,char ** start,off_t offset,int len,int * eof,void * data_unused)476 static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
477                        ,int *eof, void *data_unused)
478 {
479   unsigned long flags;
480   int i = 0;
481   int num_to_show;
482 	struct fasttime_t tv;
483   struct fast_timer *t, *nextt;
484   static char *bigbuf = NULL;
485   static unsigned long used;
486 
487 	if (!bigbuf) {
488 		bigbuf = vmalloc(BIG_BUF_SIZE);
489 		if (!bigbuf) {
490 			used = 0;
491 			if (buf)
492 				buf[0] = '\0';
493 			return 0;
494 		}
495 	}
496 
497 	if (!offset || !used) {
498     do_gettimeofday_fast(&tv);
499 
500     used = 0;
501     used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
502                     fast_timers_added);
503     used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
504                     fast_timers_started);
505     used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
506                     fast_timer_ints);
507     used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
508                     fast_timers_expired);
509     used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
510                     fast_timers_deleted);
511     used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
512                     fast_timer_running ? "yes" : "no");
513     used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
514 			(unsigned long)tv.tv_jiff,
515                     (unsigned long)tv.tv_usec);
516 #ifdef FAST_TIMER_SANITY_CHECKS
517     used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
518                     sanity_failed);
519 #endif
520     used += sprintf(bigbuf + used, "\n");
521 
522 #ifdef DEBUG_LOG_INCLUDED
523     {
524       int end_i = debug_log_cnt;
525       i = 0;
526 
527 			if (debug_log_cnt_wrapped)
528         i = debug_log_cnt;
529 
530       while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
531              used+100 < BIG_BUF_SIZE)
532       {
533         used += sprintf(bigbuf + used, debug_log_string[i],
534                         debug_log_value[i]);
535         i = (i+1) % DEBUG_LOG_MAX;
536       }
537     }
538     used += sprintf(bigbuf + used, "\n");
539 #endif
540 
541     num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
542                    NUM_TIMER_STATS);
543     used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
544     for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
545     {
546       int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
547 
548 #if 1 //ndef FAST_TIMER_LOG
549       used += sprintf(bigbuf + used, "div: %i delay: %i"
550                       "\n",
551                       timer_div_settings[cur],
552                       timer_delay_settings[cur]
553                       );
554 #endif
555 #ifdef FAST_TIMER_LOG
556       t = &timer_started_log[cur];
557       used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
558                       "d: %6li us data: 0x%08lX"
559                       "\n",
560                       t->name,
561 				(unsigned long)t->tv_set.tv_jiff,
562                       (unsigned long)t->tv_set.tv_usec,
563 				(unsigned long)t->tv_expires.tv_jiff,
564                       (unsigned long)t->tv_expires.tv_usec,
565                       t->delay_us,
566                       t->data
567                       );
568 #endif
569     }
570     used += sprintf(bigbuf + used, "\n");
571 
572 #ifdef FAST_TIMER_LOG
573     num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
574                    NUM_TIMER_STATS);
575     used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
576     for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
577     {
578       t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
579       used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
580                       "d: %6li us data: 0x%08lX"
581                       "\n",
582                       t->name,
583 				(unsigned long)t->tv_set.tv_jiff,
584                       (unsigned long)t->tv_set.tv_usec,
585 				(unsigned long)t->tv_expires.tv_jiff,
586                       (unsigned long)t->tv_expires.tv_usec,
587                       t->delay_us,
588                       t->data
589                       );
590     }
591     used += sprintf(bigbuf + used, "\n");
592 
593     num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
594                    NUM_TIMER_STATS);
595     used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
596     for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
597     {
598       t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
599       used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
600                       "d: %6li us data: 0x%08lX"
601                       "\n",
602                       t->name,
603 				(unsigned long)t->tv_set.tv_jiff,
604                       (unsigned long)t->tv_set.tv_usec,
605 				(unsigned long)t->tv_expires.tv_jiff,
606                       (unsigned long)t->tv_expires.tv_usec,
607                       t->delay_us,
608                       t->data
609                       );
610     }
611     used += sprintf(bigbuf + used, "\n");
612 #endif
613 
614     used += sprintf(bigbuf + used, "Active timers:\n");
615     local_irq_save(flags);
616     t = fast_timer_list;
617     while (t != NULL && (used+100 < BIG_BUF_SIZE))
618     {
619       nextt = t->next;
620       local_irq_restore(flags);
621       used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
622 			"d: %6li us data: 0x%08lX"
623 /*			" func: 0x%08lX" */
624 			"\n",
625 			t->name,
626 			(unsigned long)t->tv_set.tv_jiff,
627 			(unsigned long)t->tv_set.tv_usec,
628 			(unsigned long)t->tv_expires.tv_jiff,
629 			(unsigned long)t->tv_expires.tv_usec,
630                       t->delay_us,
631                       t->data
632 /*                      , t->function */
633                       );
634 			local_irq_save(flags);
635       if (t->next != nextt)
636       {
637         printk("timer removed!\n");
638       }
639       t = nextt;
640     }
641     local_irq_restore(flags);
642   }
643 
644   if (used - offset < len)
645   {
646     len = used - offset;
647   }
648 
649   memcpy(buf, bigbuf + offset, len);
650   *start = buf;
651   *eof = 1;
652 
653   return len;
654 }
655 #endif /* PROC_FS */
656 
657 #ifdef FAST_TIMER_TEST
658 static volatile unsigned long i = 0;
659 static volatile int num_test_timeout = 0;
660 static struct fast_timer tr[10];
661 static int exp_num[10];
662 
663 static struct fasttime_t tv_exp[100];
664 
test_timeout(unsigned long data)665 static void test_timeout(unsigned long data)
666 {
667   do_gettimeofday_fast(&tv_exp[data]);
668   exp_num[data] = num_test_timeout;
669 
670   num_test_timeout++;
671 }
672 
test_timeout1(unsigned long data)673 static void test_timeout1(unsigned long data)
674 {
675   do_gettimeofday_fast(&tv_exp[data]);
676   exp_num[data] = num_test_timeout;
677   if (data < 7)
678   {
679     start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
680     i++;
681   }
682   num_test_timeout++;
683 }
684 
685 DP(
686 static char buf0[2000];
687 static char buf1[2000];
688 static char buf2[2000];
689 static char buf3[2000];
690 static char buf4[2000];
691 );
692 
693 static char buf5[6000];
694 static int j_u[1000];
695 
fast_timer_test(void)696 static void fast_timer_test(void)
697 {
698   int prev_num;
699   int j;
700 
701 	struct fasttime_t tv, tv0, tv1, tv2;
702 
703   printk("fast_timer_test() start\n");
704   do_gettimeofday_fast(&tv);
705 
706   for (j = 0; j < 1000; j++)
707   {
708     j_u[j] = GET_JIFFIES_USEC();
709   }
710   for (j = 0; j < 100; j++)
711   {
712     do_gettimeofday_fast(&tv_exp[j]);
713   }
714   printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec);
715 
716   for (j = 0; j < 1000; j++)
717   {
718     printk(KERN_DEBUG "%i %i %i %i %i\n",
719       j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
720     j += 4;
721   }
722   for (j = 0; j < 100; j++)
723   {
724     printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
725 			tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
726 			tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
727 			tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
728 			tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
729 			tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
730     j += 4;
731   }
732   do_gettimeofday_fast(&tv0);
733   start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
734   DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
735   i++;
736   start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
737   DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
738   i++;
739   start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
740   DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
741   i++;
742   start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
743   DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
744   i++;
745   start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
746   DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
747   i++;
748   do_gettimeofday_fast(&tv1);
749 
750   proc_fasttimer_read(buf5, NULL, 0, 0, 0);
751 
752   prev_num = num_test_timeout;
753   while (num_test_timeout < i)
754   {
755     if (num_test_timeout != prev_num)
756       prev_num = num_test_timeout;
757   }
758   do_gettimeofday_fast(&tv2);
759 	printk(KERN_INFO "Timers started    %is %06i\n",
760 		tv0.tv_jiff, tv0.tv_usec);
761 	printk(KERN_INFO "Timers started at %is %06i\n",
762 		tv1.tv_jiff, tv1.tv_usec);
763 	printk(KERN_INFO "Timers done       %is %06i\n",
764 		tv2.tv_jiff, tv2.tv_usec);
765   DP(printk("buf0:\n");
766      printk(buf0);
767      printk("buf1:\n");
768      printk(buf1);
769      printk("buf2:\n");
770      printk(buf2);
771      printk("buf3:\n");
772      printk(buf3);
773      printk("buf4:\n");
774      printk(buf4);
775   );
776   printk("buf5:\n");
777   printk(buf5);
778 
779   printk("timers set:\n");
780   for(j = 0; j<i; j++)
781   {
782     struct fast_timer *t = &tr[j];
783     printk("%-10s set: %6is %06ius exp: %6is %06ius "
784            "data: 0x%08X func: 0x%08X\n",
785            t->name,
786 			t->tv_set.tv_jiff,
787            t->tv_set.tv_usec,
788 			t->tv_expires.tv_jiff,
789            t->tv_expires.tv_usec,
790            t->data,
791            t->function
792            );
793 
794     printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
795            t->delay_us,
796 			tv_exp[j].tv_jiff,
797            tv_exp[j].tv_usec,
798            exp_num[j],
799 			(tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
800 				1000000 + tv_exp[j].tv_usec -
801 				t->tv_expires.tv_usec);
802   }
803   proc_fasttimer_read(buf5, NULL, 0, 0, 0);
804   printk("buf5 after all done:\n");
805   printk(buf5);
806   printk("fast_timer_test() done\n");
807 }
808 #endif
809 
810 
fast_timer_init(void)811 int fast_timer_init(void)
812 {
813   /* For some reason, request_irq() hangs when called froom time_init() */
814   if (!fast_timer_is_init)
815   {
816     printk("fast_timer_init()\n");
817 
818 #ifdef CONFIG_PROC_FS
819     fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0);
820     if (fasttimer_proc_entry)
821       fasttimer_proc_entry->read_proc = proc_fasttimer_read;
822 #endif /* PROC_FS */
823 		if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
824 				IRQF_SHARED | IRQF_DISABLED,
825 				"fast timer int", &fast_timer_list))
826 			printk(KERN_ERR "err: fasttimer irq\n");
827     fast_timer_is_init = 1;
828 #ifdef FAST_TIMER_TEST
829     printk("do test\n");
830     fast_timer_test();
831 #endif
832   }
833 	return 0;
834 }
835 __initcall(fast_timer_init);
836