diff options
Diffstat (limited to 'arch/cris/arch-v10/kernel/fasttimer.c')
| -rw-r--r-- | arch/cris/arch-v10/kernel/fasttimer.c | 650 |
1 files changed, 256 insertions, 394 deletions
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index cac05a5e514..48a59afbeeb 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -1,97 +1,9 @@ -/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $ +/* * linux/arch/cris/kernel/fasttimer.c * * Fast timers for ETRAX100/ETRAX100LX - * This may be useful in other OS than Linux so use 2 space indentation... * - * $Log: fasttimer.c,v $ - * Revision 1.9 2005/03/04 08:16:16 starvik - * Merge of Linux 2.6.11. - * - * Revision 1.8 2005/01/05 06:09:29 starvik - * cli()/sti() will be obsolete in 2.6.11. - * - * Revision 1.7 2005/01/03 13:35:46 starvik - * Removed obsolete stuff. - * Mark fast timer IRQ as not shared. - * - * Revision 1.6 2004/05/14 10:18:39 starvik - * Export fast_timer_list - * - * Revision 1.5 2004/05/14 07:58:01 starvik - * Merge of changes from 2.4 - * - * Revision 1.4 2003/07/04 08:27:41 starvik - * Merge of Linux 2.5.74 - * - * Revision 1.3 2002/12/12 08:26:32 starvik - * Don't use C-comments inside CVS comments - * - * Revision 1.2 2002/12/11 15:42:02 starvik - * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ - * - * Revision 1.1 2002/11/18 07:58:06 starvik - * Fast timers (from Linux 2.4) - * - * Revision 1.5 2002/10/15 06:21:39 starvik - * Added call to init_waitqueue_head - * - * Revision 1.4 2002/05/28 17:47:59 johana - * Added del_fast_timer() - * - * Revision 1.3 2002/05/28 16:16:07 johana - * Handle empty fast_timer_list - * - * Revision 1.2 2002/05/27 15:38:42 johana - * Made it compile without warnings on Linux 2.4. - * (includes, wait_queue, PROC_FS and snprintf) - * - * Revision 1.1 2002/05/27 15:32:25 johana - * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. - * - * Revision 1.8 2001/11/27 13:50:40 pkj - * Disable interrupts while stopping the timer and while modifying the - * list of active timers in timer1_handler() as it may be interrupted - * by other interrupts (e.g., the serial interrupt) which may add fast - * timers. - * - * Revision 1.7 2001/11/22 11:50:32 pkj - * * Only store information about the last 16 timers. - * * proc_fasttimer_read() now uses an allocated buffer, since it - * requires more space than just a page even for only writing the - * last 16 timers. The buffer is only allocated on request, so - * unless /proc/fasttimer is read, it is never allocated. - * * Renamed fast_timer_started to fast_timers_started to match - * fast_timers_added and fast_timers_expired. - * * Some clean-up. - * - * Revision 1.6 2000/12/13 14:02:08 johana - * Removed volatile for fast_timer_list - * - * Revision 1.5 2000/12/13 13:55:35 johana - * Added DEBUG_LOG, added som cli() and cleanup - * - * Revision 1.4 2000/12/05 13:48:50 johana - * Added range check when writing proc file, modified timer int handling - * - * Revision 1.3 2000/11/23 10:10:20 johana - * More debug/logging possibilities. - * Moved GET_JIFFIES_USEC() to timex.h and time.c - * - * Revision 1.2 2000/11/01 13:41:04 johana - * Clean up and bugfixes. - * Created new do_gettimeofday_fast() that gets a timeval struct - * with time based on jiffies and *R_TIMER0_DATA, uses a table - * for fast conversion of timer value to microseconds. - * (Much faster the standard do_gettimeofday() and we don't really - * wan't to use the true time - we wan't the "uptime" so timers don't screw up - * when we change the time. - * TODO: Add efficient support for continuous timers as well. - * - * Revision 1.1 2000/10/26 15:49:16 johana - * Added fasttimer, highresolution timers. - * - * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden + * Copyright (C) 2000-2007 Axis Communications AB, Lund, Sweden */ #include <linux/errno.h> @@ -109,41 +21,34 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/delay.h> -#include <asm/rtc.h> - -#include <linux/config.h> -#include <asm/arch/svinto.h> +#include <arch/svinto.h> #include <asm/fasttimer.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #define DEBUG_LOG_INCLUDED #define FAST_TIMER_LOG -//#define FAST_TIMER_TEST +/* #define FAST_TIMER_TEST */ #define FAST_TIMER_SANITY_CHECKS #ifdef FAST_TIMER_SANITY_CHECKS -#define SANITYCHECK(x) x -static int sanity_failed = 0; -#else -#define SANITYCHECK(x) +static int sanity_failed; #endif #define D1(x) #define D2(x) #define DP(x) -#define __INLINE__ inline - -static int fast_timer_running = 0; -static int fast_timers_added = 0; -static int fast_timers_started = 0; -static int fast_timers_expired = 0; -static int fast_timers_deleted = 0; -static int fast_timer_is_init = 0; -static int fast_timer_ints = 0; +static unsigned int fast_timer_running; +static unsigned int fast_timers_added; +static unsigned int fast_timers_started; +static unsigned int fast_timers_expired; +static unsigned int fast_timers_deleted; +static unsigned int fast_timer_is_init; +static unsigned int fast_timer_ints; struct fast_timer *fast_timer_list = NULL; @@ -151,8 +56,8 @@ struct fast_timer *fast_timer_list = NULL; #define DEBUG_LOG_MAX 128 static const char * debug_log_string[DEBUG_LOG_MAX]; static unsigned long debug_log_value[DEBUG_LOG_MAX]; -static int debug_log_cnt = 0; -static int debug_log_cnt_wrapped = 0; +static unsigned int debug_log_cnt; +static unsigned int debug_log_cnt_wrapped; #define DEBUG_LOG(string, value) \ { \ @@ -207,45 +112,29 @@ int timer_freq_settings[NUM_TIMER_STATS]; int timer_delay_settings[NUM_TIMER_STATS]; /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ -void __INLINE__ do_gettimeofday_fast(struct timeval *tv) +inline void do_gettimeofday_fast(struct fasttime_t *tv) { - unsigned long sec = jiffies; - unsigned long usec = GET_JIFFIES_USEC(); - - usec += (sec % HZ) * (1000000 / HZ); - sec = sec / HZ; - - if (usec > 1000000) - { - usec -= 1000000; - sec++; - } - tv->tv_sec = sec; - tv->tv_usec = usec; + tv->tv_jiff = jiffies; + tv->tv_usec = GET_JIFFIES_USEC(); } -int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) +inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1) { - if (t0->tv_sec < t1->tv_sec) - { - return -1; - } - else if (t0->tv_sec > t1->tv_sec) - { - return 1; - } - if (t0->tv_usec < t1->tv_usec) - { - return -1; - } - else if (t0->tv_usec > t1->tv_usec) - { - return 1; - } - return 0; + /* Compare jiffies. Takes care of wrapping */ + if (time_before(t0->tv_jiff, t1->tv_jiff)) + return -1; + else if (time_after(t0->tv_jiff, t1->tv_jiff)) + return 1; + + /* Compare us */ + if (t0->tv_usec < t1->tv_usec) + return -1; + else if (t0->tv_usec > t1->tv_usec) + return 1; + return 0; } -void __INLINE__ start_timer1(unsigned long delay_us) +inline void start_timer1(unsigned long delay_us) { int freq_index = 0; /* This is the lowest resolution */ unsigned long upper_limit = MAX_DELAY_US; @@ -286,7 +175,7 @@ void __INLINE__ start_timer1(unsigned long delay_us) timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; - D1(printk("start_timer1 : %d us freq: %i div: %i\n", + D1(printk(KERN_DEBUG "start_timer1 : %d us freq: %i div: %i\n", delay_us, freq_index, div)); /* Clear timer1 irq */ *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); @@ -333,23 +222,19 @@ void start_one_shot_timer(struct fast_timer *t, do_gettimeofday_fast(&t->tv_set); tmp = fast_timer_list; - SANITYCHECK({ /* Check so this is not in the list already... */ - while (tmp != NULL) - { - if (tmp == t) - { - printk(KERN_WARNING - "timer name: %s data: 0x%08lX already in list!\n", name, data); - sanity_failed++; - return; - } - else - { - tmp = tmp->next; - } - } - tmp = fast_timer_list; - }); +#ifdef FAST_TIMER_SANITY_CHECKS + /* Check so this is not in the list already... */ + while (tmp != NULL) { + if (tmp == t) { + printk(KERN_WARNING "timer name: %s data: " + "0x%08lX already in list!\n", name, data); + sanity_failed++; + goto done; + } else + tmp = tmp->next; + } + tmp = fast_timer_list; +#endif t->delay_us = delay_us; t->function = function; @@ -357,11 +242,11 @@ void start_one_shot_timer(struct fast_timer *t, t->name = name; t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; - t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; + t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ; if (t->tv_expires.tv_usec > 1000000) { t->tv_expires.tv_usec -= 1000000; - t->tv_expires.tv_sec++; + t->tv_expires.tv_jiff += HZ; } #ifdef FAST_TIMER_LOG timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; @@ -369,7 +254,7 @@ void start_one_shot_timer(struct fast_timer *t, fast_timers_added++; /* Check if this should timeout before anything else */ - if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) + if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) { /* Put first in list and modify the timer value */ t->prev = NULL; @@ -385,8 +270,8 @@ void start_one_shot_timer(struct fast_timer *t, start_timer1(delay_us); } else { /* Put in correct place in list */ - while (tmp->next && - timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) + while (tmp->next && fasttime_cmp(&t->tv_expires, + &tmp->next->tv_expires) > 0) { tmp = tmp->next; } @@ -402,6 +287,7 @@ void start_one_shot_timer(struct fast_timer *t, D2(printk("start_one_shot_timer: %d us done\n", delay_us)); +done: local_irq_restore(flags); } /* start_one_shot_timer */ @@ -445,11 +331,18 @@ int del_fast_timer(struct fast_timer * t) /* Timer 1 interrupt handler */ static irqreturn_t -timer1_handler(int irq, void *dev_id, struct pt_regs *regs) +timer1_handler(int irq, void *dev_id) { struct fast_timer *t; unsigned long flags; + /* We keep interrupts disabled not only when we modify the + * fast timer list, but any time we hold a reference to a + * timer in the list, since del_fast_timer may be called + * from (another) interrupt context. Thus, the only time + * when interrupts are enabled is when calling the timer + * callback function. + */ local_irq_save(flags); /* Clear timer1 irq */ @@ -467,18 +360,19 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timer_running = 0; fast_timer_ints++; - local_irq_restore(flags); - t = fast_timer_list; while (t) { - struct timeval tv; + struct fasttime_t tv; + fast_timer_function_type *f; + unsigned long d; /* Has it really expired? */ do_gettimeofday_fast(&tv); - D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); + D1(printk(KERN_DEBUG "t: %is %06ius\n", + tv.tv_jiff, tv.tv_usec)); - if (timeval_cmp(&t->tv_expires, &tv) <= 0) + if (fasttime_cmp(&t->tv_expires, &tv) <= 0) { /* Yes it has expired */ #ifdef FAST_TIMER_LOG @@ -487,7 +381,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timers_expired++; /* Remove this timer before call, since it may reuse the timer */ - local_irq_save(flags); if (t->prev) { t->prev->next = t->next; @@ -502,16 +395,23 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) } t->prev = NULL; t->next = NULL; - local_irq_restore(flags); - if (t->function != NULL) - { - t->function(t->data); - } - else - { + /* Save function callback data before enabling + * interrupts, since the timer may be removed and + * we don't know how it was allocated + * (e.g. ->function and ->data may become overwritten + * after deletion if the timer was stack-allocated). + */ + f = t->function; + d = t->data; + + if (f != NULL) { + /* Run callback with interrupts enabled. */ + local_irq_restore(flags); + f(d); + local_irq_save(flags); + } else DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); - } } else { @@ -519,16 +419,20 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk(".\n")); } - local_irq_save(flags); if ((t = fast_timer_list) != NULL) { /* Start next timer.. */ - long us; - struct timeval tv; + long us = 0; + struct fasttime_t tv; do_gettimeofday_fast(&tv); - us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + - t->tv_expires.tv_usec - tv.tv_usec); + + /* time_after_eq takes care of wrapping */ + if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff)) + us = ((t->tv_expires.tv_jiff - tv.tv_jiff) * + 1000000 / HZ + t->tv_expires.tv_usec - + tv.tv_usec); + if (us > 0) { if (!fast_timer_running) @@ -538,7 +442,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) #endif start_timer1(us); } - local_irq_restore(flags); break; } else @@ -549,9 +452,10 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk("e! %d\n", us)); } } - local_irq_restore(flags); } + local_irq_restore(flags); + if (!t) { D1(printk("t1 stop!\n")); @@ -562,11 +466,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) static void wake_up_func(unsigned long data) { -#ifdef DECLARE_WAITQUEUE - wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; -#else - struct wait_queue **sleep_wait_p = (struct wait_queue **)data; -#endif + wait_queue_head_t *sleep_wait_p = (wait_queue_head_t *)data; wake_up(sleep_wait_p); } @@ -576,221 +476,176 @@ static void wake_up_func(unsigned long data) void schedule_usleep(unsigned long us) { struct fast_timer t; -#ifdef DECLARE_WAITQUEUE wait_queue_head_t sleep_wait; init_waitqueue_head(&sleep_wait); - { - DECLARE_WAITQUEUE(wait, current); -#else - struct wait_queue *sleep_wait = NULL; - struct wait_queue wait = { current, NULL }; -#endif D1(printk("schedule_usleep(%d)\n", us)); - add_wait_queue(&sleep_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, "usleep"); - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&sleep_wait, &wait); + /* Uninterruptible sleep on the fast timer. (The condition is somewhat + * redundant since the timer is what wakes us up.) */ + wait_event(sleep_wait, !fast_timer_pending(&t)); + D1(printk("done schedule_usleep(%d)\n", us)); -#ifdef DECLARE_WAITQUEUE - } -#endif } #ifdef CONFIG_PROC_FS -static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len - ,int *eof, void *data_unused); -static struct proc_dir_entry *fasttimer_proc_entry; -#endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_PROC_FS - /* This value is very much based on testing */ #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) -static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len - ,int *eof, void *data_unused) +static int proc_fasttimer_show(struct seq_file *m, void *v) { - unsigned long flags; - int i = 0; - int num_to_show; - struct timeval tv; - struct fast_timer *t, *nextt; - static char *bigbuf = NULL; - static unsigned long used; - - if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) - { - used = 0; - bigbuf[0] = '\0'; - return 0; - } - - if (!offset || !used) - { - do_gettimeofday_fast(&tv); - - used = 0; - used += sprintf(bigbuf + used, "Fast timers added: %i\n", - fast_timers_added); - used += sprintf(bigbuf + used, "Fast timers started: %i\n", - fast_timers_started); - used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n", - fast_timer_ints); - used += sprintf(bigbuf + used, "Fast timers expired: %i\n", - fast_timers_expired); - used += sprintf(bigbuf + used, "Fast timers deleted: %i\n", - fast_timers_deleted); - used += sprintf(bigbuf + used, "Fast timer running: %s\n", - fast_timer_running ? "yes" : "no"); - used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", - (unsigned long)tv.tv_sec, - (unsigned long)tv.tv_usec); + unsigned long flags; + int i = 0; + int num_to_show; + struct fasttime_t tv; + struct fast_timer *t, *nextt; + + do_gettimeofday_fast(&tv); + + seq_printf(m, "Fast timers added: %i\n", fast_timers_added); + seq_printf(m, "Fast timers started: %i\n", fast_timers_started); + seq_printf(m, "Fast timer interrupts: %i\n", fast_timer_ints); + seq_printf(m, "Fast timers expired: %i\n", fast_timers_expired); + seq_printf(m, "Fast timers deleted: %i\n", fast_timers_deleted); + seq_printf(m, "Fast timer running: %s\n", + fast_timer_running ? "yes" : "no"); + seq_printf(m, "Current time: %lu.%06lu\n", + (unsigned long)tv.tv_jiff, + (unsigned long)tv.tv_usec); #ifdef FAST_TIMER_SANITY_CHECKS - used += sprintf(bigbuf + used, "Sanity failed: %i\n", - sanity_failed); + seq_printf(m, "Sanity failed: %i\n", sanity_failed); #endif - used += sprintf(bigbuf + used, "\n"); + seq_putc(m, '\n'); #ifdef DEBUG_LOG_INCLUDED - { - int end_i = debug_log_cnt; - i = 0; - - if (debug_log_cnt_wrapped) - { - i = debug_log_cnt; - } - - while ((i != end_i || (debug_log_cnt_wrapped && !used)) && - used+100 < BIG_BUF_SIZE) - { - used += sprintf(bigbuf + used, debug_log_string[i], - debug_log_value[i]); - i = (i+1) % DEBUG_LOG_MAX; - } - } - used += sprintf(bigbuf + used, "\n"); + { + int end_i = debug_log_cnt; + i = 0; + + if (debug_log_cnt_wrapped) + i = debug_log_cnt; + + while (i != end_i || debug_log_cnt_wrapped) { + if (seq_printf(m, debug_log_string[i], debug_log_value[i]) < 0) + return 0; + i = (i+1) % DEBUG_LOG_MAX; + } + } + seq_putc(m, '\n'); #endif - num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: - NUM_TIMER_STATS); - used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started); - for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++) - { - int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; + num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: + NUM_TIMER_STATS); + seq_printf(m, "Timers started: %i\n", fast_timers_started); + for (i = 0; i < num_to_show; i++) { + int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; #if 1 //ndef FAST_TIMER_LOG - used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i" - "\n", - timer_div_settings[cur], - timer_freq_settings[cur], - timer_delay_settings[cur] - ); + seq_printf(m, "div: %i freq: %i delay: %i" + "\n", + timer_div_settings[cur], + timer_freq_settings[cur], + timer_delay_settings[cur]); #endif #ifdef FAST_TIMER_LOG - t = &timer_started_log[cur]; - used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " - "d: %6li us data: 0x%08lX" - "\n", - t->name, - (unsigned long)t->tv_set.tv_sec, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data - ); + t = &timer_started_log[cur]; + if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_jiff, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_jiff, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data) < 0) + return 0; #endif - } - used += sprintf(bigbuf + used, "\n"); + } + seq_putc(m, '\n'); #ifdef FAST_TIMER_LOG - num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: - NUM_TIMER_STATS); - used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added); - for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) - { - t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; - used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " - "d: %6li us data: 0x%08lX" - "\n", - t->name, - (unsigned long)t->tv_set.tv_sec, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data - ); - } - used += sprintf(bigbuf + used, "\n"); - - num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: - NUM_TIMER_STATS); - used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired); - for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) - { - t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; - used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " - "d: %6li us data: 0x%08lX" - "\n", - t->name, - (unsigned long)t->tv_set.tv_sec, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data - ); - } - used += sprintf(bigbuf + used, "\n"); + num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: + NUM_TIMER_STATS); + seq_printf(m, "Timers added: %i\n", fast_timers_added); + for (i = 0; i < num_to_show; i++) { + t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; + if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_jiff, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_jiff, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data) < 0) + return 0; + } + seq_putc(m, '\n'); + + num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: + NUM_TIMER_STATS); + seq_printf(m, "Timers expired: %i\n", fast_timers_expired); + for (i = 0; i < num_to_show; i++) { + t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; + if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_jiff, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_jiff, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data) < 0) + return 0; + } + seq_putc(m, '\n'); #endif - used += sprintf(bigbuf + used, "Active timers:\n"); - local_irq_save(flags); - t = fast_timer_list; - while (t != NULL && (used+100 < BIG_BUF_SIZE)) - { - nextt = t->next; - local_irq_restore(flags); - used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " - "d: %6li us data: 0x%08lX" + seq_puts(m, "Active timers:\n"); + local_irq_save(flags); + t = fast_timer_list; + while (t) { + nextt = t->next; + local_irq_restore(flags); + if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" /* " func: 0x%08lX" */ - "\n", - t->name, - (unsigned long)t->tv_set.tv_sec, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data + "\n", + t->name, + (unsigned long)t->tv_set.tv_jiff, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_jiff, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data /* , t->function */ - ); - local_irq_disable(); - if (t->next != nextt) - { - printk(KERN_WARNING "timer removed!\n"); - } - t = nextt; - } - local_irq_restore(flags); - } - - if (used - offset < len) - { - len = used - offset; - } - - memcpy(buf, bigbuf + offset, len); - *start = buf; - *eof = 1; + ) < 0) + return 0; + local_irq_save(flags); + if (t->next != nextt) + printk(KERN_WARNING "timer removed!\n"); + t = nextt; + } + local_irq_restore(flags); + + return 0; +} - return len; +static int proc_fasttimer_open(struct inode *inode, struct file *file) +{ + return single_open_size(file, proc_fasttimer_show, PDE_DATA(inode), BIG_BUF_SIZE); } + +static const struct file_operations proc_fasttimer_fops = { + .open = proc_fasttimer_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif /* PROC_FS */ #ifdef FAST_TIMER_TEST @@ -799,7 +654,7 @@ static volatile int num_test_timeout = 0; static struct fast_timer tr[10]; static int exp_num[10]; -static struct timeval tv_exp[100]; +static struct fasttime_t tv_exp[100]; static void test_timeout(unsigned long data) { @@ -837,7 +692,7 @@ static void fast_timer_test(void) int prev_num; int j; - struct timeval tv, tv0, tv1, tv2; + struct fasttime_t tv, tv0, tv1, tv2; printk("fast_timer_test() start\n"); do_gettimeofday_fast(&tv); @@ -850,7 +705,8 @@ static void fast_timer_test(void) { do_gettimeofday_fast(&tv_exp[j]); } - printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); + printk(KERN_DEBUG "fast_timer_test() %is %06i\n", + tv.tv_jiff, tv.tv_usec); for (j = 0; j < 1000; j++) { @@ -859,12 +715,12 @@ static void fast_timer_test(void) } for (j = 0; j < 100; j++) { - printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", - tv_exp[j].tv_sec,tv_exp[j].tv_usec, - tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, - tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, - tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, - tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); + printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n", + tv_exp[j].tv_jiff, tv_exp[j].tv_usec, + tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec, + tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec, + tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec, + tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec); j += 4; } do_gettimeofday_fast(&tv0); @@ -896,9 +752,12 @@ static void fast_timer_test(void) } } do_gettimeofday_fast(&tv2); - printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); - printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); - printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); + printk(KERN_DEBUG "Timers started %is %06i\n", + tv0.tv_jiff, tv0.tv_usec); + printk(KERN_DEBUG "Timers started at %is %06i\n", + tv1.tv_jiff, tv1.tv_usec); + printk(KERN_DEBUG "Timers done %is %06i\n", + tv2.tv_jiff, tv2.tv_usec); DP(printk("buf0:\n"); printk(buf0); printk("buf1:\n"); @@ -920,9 +779,9 @@ static void fast_timer_test(void) printk("%-10s set: %6is %06ius exp: %6is %06ius " "data: 0x%08X func: 0x%08X\n", t->name, - t->tv_set.tv_sec, + t->tv_set.tv_jiff, t->tv_set.tv_usec, - t->tv_expires.tv_sec, + t->tv_expires.tv_jiff, t->tv_expires.tv_usec, t->data, t->function @@ -930,10 +789,12 @@ static void fast_timer_test(void) printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", t->delay_us, - tv_exp[j].tv_sec, + tv_exp[j].tv_jiff, tv_exp[j].tv_usec, exp_num[j], - (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); + (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) * + 1000000 + tv_exp[j].tv_usec - + t->tv_expires.tv_usec); } proc_fasttimer_read(buf5, NULL, 0, 0, 0); printk("buf5 after all done:\n"); @@ -943,7 +804,7 @@ static void fast_timer_test(void) #endif -void fast_timer_init(void) +int fast_timer_init(void) { /* For some reason, request_irq() hangs when called froom time_init() */ if (!fast_timer_is_init) @@ -962,8 +823,7 @@ void fast_timer_init(void) } #endif #ifdef CONFIG_PROC_FS - if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) - fasttimer_proc_entry->read_proc = proc_fasttimer_read; + proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops); #endif /* PROC_FS */ if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0, "fast timer int", NULL)) @@ -976,4 +836,6 @@ void fast_timer_init(void) fast_timer_test(); #endif } + return 0; } +__initcall(fast_timer_init); |
