Path: blob/master/arch/cris/arch-v10/kernel/fasttimer.c
15125 views
/*1* linux/arch/cris/kernel/fasttimer.c2*3* Fast timers for ETRAX100/ETRAX100LX4*5* Copyright (C) 2000-2007 Axis Communications AB, Lund, Sweden6*/78#include <linux/errno.h>9#include <linux/sched.h>10#include <linux/kernel.h>11#include <linux/param.h>12#include <linux/string.h>13#include <linux/mm.h>14#include <linux/vmalloc.h>15#include <linux/interrupt.h>16#include <linux/time.h>17#include <linux/delay.h>1819#include <asm/segment.h>20#include <asm/io.h>21#include <asm/irq.h>22#include <asm/delay.h>23#include <asm/rtc.h>242526#include <arch/svinto.h>27#include <asm/fasttimer.h>28#include <linux/proc_fs.h>293031#define DEBUG_LOG_INCLUDED32#define FAST_TIMER_LOG33/* #define FAST_TIMER_TEST */3435#define FAST_TIMER_SANITY_CHECKS3637#ifdef FAST_TIMER_SANITY_CHECKS38static int sanity_failed;39#endif4041#define D1(x)42#define D2(x)43#define DP(x)4445static unsigned int fast_timer_running;46static unsigned int fast_timers_added;47static unsigned int fast_timers_started;48static unsigned int fast_timers_expired;49static unsigned int fast_timers_deleted;50static unsigned int fast_timer_is_init;51static unsigned int fast_timer_ints;5253struct fast_timer *fast_timer_list = NULL;5455#ifdef DEBUG_LOG_INCLUDED56#define DEBUG_LOG_MAX 12857static const char * debug_log_string[DEBUG_LOG_MAX];58static unsigned long debug_log_value[DEBUG_LOG_MAX];59static unsigned int debug_log_cnt;60static unsigned int debug_log_cnt_wrapped;6162#define DEBUG_LOG(string, value) \63{ \64unsigned long log_flags; \65local_irq_save(log_flags); \66debug_log_string[debug_log_cnt] = (string); \67debug_log_value[debug_log_cnt] = (unsigned long)(value); \68if (++debug_log_cnt >= DEBUG_LOG_MAX) \69{ \70debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \71debug_log_cnt_wrapped = 1; \72} \73local_irq_restore(log_flags); \74}75#else76#define DEBUG_LOG(string, value)77#endif787980/* The frequencies for index = clkselx number in R_TIMER_CTRL */81#define NUM_TIMER_FREQ 1582#define MAX_USABLE_TIMER_FREQ 783#define MAX_DELAY_US 853333L84const unsigned long timer_freq_100[NUM_TIMER_FREQ] =85{863, /* 0 3333 - 853333 us */876, /* 1 1666 - 426666 us */8812, /* 2 833 - 213333 us */8924, /* 3 416 - 106666 us */9048, /* 4 208 - 53333 us */9196, /* 5 104 - 26666 us */92192, /* 6 52 - 13333 us */93384, /* 7 26 - 6666 us */94576,951152,962304,974608,989216,9918432,10062500,101/* 15 = cascade */102};103#define NUM_TIMER_STATS 16104#ifdef FAST_TIMER_LOG105struct fast_timer timer_added_log[NUM_TIMER_STATS];106struct fast_timer timer_started_log[NUM_TIMER_STATS];107struct fast_timer timer_expired_log[NUM_TIMER_STATS];108#endif109110int timer_div_settings[NUM_TIMER_STATS];111int timer_freq_settings[NUM_TIMER_STATS];112int timer_delay_settings[NUM_TIMER_STATS];113114/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */115inline void do_gettimeofday_fast(struct fasttime_t *tv)116{117tv->tv_jiff = jiffies;118tv->tv_usec = GET_JIFFIES_USEC();119}120121inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)122{123/* Compare jiffies. Takes care of wrapping */124if (time_before(t0->tv_jiff, t1->tv_jiff))125return -1;126else if (time_after(t0->tv_jiff, t1->tv_jiff))127return 1;128129/* Compare us */130if (t0->tv_usec < t1->tv_usec)131return -1;132else if (t0->tv_usec > t1->tv_usec)133return 1;134return 0;135}136137inline void start_timer1(unsigned long delay_us)138{139int freq_index = 0; /* This is the lowest resolution */140unsigned long upper_limit = MAX_DELAY_US;141142unsigned long div;143/* Start/Restart the timer to the new shorter value */144/* t = 1/freq = 1/19200 = 53us145* T=div*t, div = T/t = delay_us*freq/1000000146*/147#if 1 /* Adaptive timer settings */148while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)149{150freq_index++;151upper_limit >>= 1; /* Divide by 2 using shift */152}153if (freq_index > 0)154{155freq_index--;156}157#else158freq_index = 6;159#endif160div = delay_us * timer_freq_100[freq_index]/10000;161if (div < 2)162{163/* Maybe increase timer freq? */164div = 2;165}166if (div > 255)167{168div = 0; /* This means 256, the max the timer takes */169/* If a longer timeout than the timer can handle is used,170* then we must restart it when it goes off.171*/172}173174timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;175timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;176timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;177178D1(printk(KERN_DEBUG "start_timer1 : %d us freq: %i div: %i\n",179delay_us, freq_index, div));180/* Clear timer1 irq */181*R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);182183/* Set timer values */184*R_TIMER_CTRL = r_timer_ctrl_shadow =185(r_timer_ctrl_shadow &186~IO_MASK(R_TIMER_CTRL, timerdiv1) &187~IO_MASK(R_TIMER_CTRL, tm1) &188~IO_MASK(R_TIMER_CTRL, clksel1)) |189IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |190IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |191IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */192193/* Ack interrupt */194*R_TIMER_CTRL = r_timer_ctrl_shadow |195IO_STATE(R_TIMER_CTRL, i1, clr);196197/* Start timer */198*R_TIMER_CTRL = r_timer_ctrl_shadow =199(r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |200IO_STATE(R_TIMER_CTRL, tm1, run);201202/* Enable timer1 irq */203*R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);204fast_timers_started++;205fast_timer_running = 1;206}207208/* In version 1.4 this function takes 27 - 50 us */209void start_one_shot_timer(struct fast_timer *t,210fast_timer_function_type *function,211unsigned long data,212unsigned long delay_us,213const char *name)214{215unsigned long flags;216struct fast_timer *tmp;217218D1(printk("sft %s %d us\n", name, delay_us));219220local_irq_save(flags);221222do_gettimeofday_fast(&t->tv_set);223tmp = fast_timer_list;224225#ifdef FAST_TIMER_SANITY_CHECKS226/* Check so this is not in the list already... */227while (tmp != NULL) {228if (tmp == t) {229printk(KERN_WARNING "timer name: %s data: "230"0x%08lX already in list!\n", name, data);231sanity_failed++;232goto done;233} else234tmp = tmp->next;235}236tmp = fast_timer_list;237#endif238239t->delay_us = delay_us;240t->function = function;241t->data = data;242t->name = name;243244t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;245t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;246if (t->tv_expires.tv_usec > 1000000)247{248t->tv_expires.tv_usec -= 1000000;249t->tv_expires.tv_jiff += HZ;250}251#ifdef FAST_TIMER_LOG252timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;253#endif254fast_timers_added++;255256/* Check if this should timeout before anything else */257if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0)258{259/* Put first in list and modify the timer value */260t->prev = NULL;261t->next = fast_timer_list;262if (fast_timer_list)263{264fast_timer_list->prev = t;265}266fast_timer_list = t;267#ifdef FAST_TIMER_LOG268timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;269#endif270start_timer1(delay_us);271} else {272/* Put in correct place in list */273while (tmp->next && fasttime_cmp(&t->tv_expires,274&tmp->next->tv_expires) > 0)275{276tmp = tmp->next;277}278/* Insert t after tmp */279t->prev = tmp;280t->next = tmp->next;281if (tmp->next)282{283tmp->next->prev = t;284}285tmp->next = t;286}287288D2(printk("start_one_shot_timer: %d us done\n", delay_us));289290done:291local_irq_restore(flags);292} /* start_one_shot_timer */293294static inline int fast_timer_pending (const struct fast_timer * t)295{296return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);297}298299static inline int detach_fast_timer (struct fast_timer *t)300{301struct fast_timer *next, *prev;302if (!fast_timer_pending(t))303return 0;304next = t->next;305prev = t->prev;306if (next)307next->prev = prev;308if (prev)309prev->next = next;310else311fast_timer_list = next;312fast_timers_deleted++;313return 1;314}315316int del_fast_timer(struct fast_timer * t)317{318unsigned long flags;319int ret;320321local_irq_save(flags);322ret = detach_fast_timer(t);323t->next = t->prev = NULL;324local_irq_restore(flags);325return ret;326} /* del_fast_timer */327328329/* Interrupt routines or functions called in interrupt context */330331/* Timer 1 interrupt handler */332333static irqreturn_t334timer1_handler(int irq, void *dev_id)335{336struct fast_timer *t;337unsigned long flags;338339/* We keep interrupts disabled not only when we modify the340* fast timer list, but any time we hold a reference to a341* timer in the list, since del_fast_timer may be called342* from (another) interrupt context. Thus, the only time343* when interrupts are enabled is when calling the timer344* callback function.345*/346local_irq_save(flags);347348/* Clear timer1 irq */349*R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);350351/* First stop timer, then ack interrupt */352/* Stop timer */353*R_TIMER_CTRL = r_timer_ctrl_shadow =354(r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |355IO_STATE(R_TIMER_CTRL, tm1, stop_ld);356357/* Ack interrupt */358*R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);359360fast_timer_running = 0;361fast_timer_ints++;362363t = fast_timer_list;364while (t)365{366struct fasttime_t tv;367fast_timer_function_type *f;368unsigned long d;369370/* Has it really expired? */371do_gettimeofday_fast(&tv);372D1(printk(KERN_DEBUG "t: %is %06ius\n",373tv.tv_jiff, tv.tv_usec));374375if (fasttime_cmp(&t->tv_expires, &tv) <= 0)376{377/* Yes it has expired */378#ifdef FAST_TIMER_LOG379timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;380#endif381fast_timers_expired++;382383/* Remove this timer before call, since it may reuse the timer */384if (t->prev)385{386t->prev->next = t->next;387}388else389{390fast_timer_list = t->next;391}392if (t->next)393{394t->next->prev = t->prev;395}396t->prev = NULL;397t->next = NULL;398399/* Save function callback data before enabling400* interrupts, since the timer may be removed and401* we don't know how it was allocated402* (e.g. ->function and ->data may become overwritten403* after deletion if the timer was stack-allocated).404*/405f = t->function;406d = t->data;407408if (f != NULL) {409/* Run callback with interrupts enabled. */410local_irq_restore(flags);411f(d);412local_irq_save(flags);413} else414DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);415}416else417{418/* Timer is to early, let's set it again using the normal routines */419D1(printk(".\n"));420}421422if ((t = fast_timer_list) != NULL)423{424/* Start next timer.. */425long us = 0;426struct fasttime_t tv;427428do_gettimeofday_fast(&tv);429430/* time_after_eq takes care of wrapping */431if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))432us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *4331000000 / HZ + t->tv_expires.tv_usec -434tv.tv_usec);435436if (us > 0)437{438if (!fast_timer_running)439{440#ifdef FAST_TIMER_LOG441timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;442#endif443start_timer1(us);444}445break;446}447else448{449/* Timer already expired, let's handle it better late than never.450* The normal loop handles it451*/452D1(printk("e! %d\n", us));453}454}455}456457local_irq_restore(flags);458459if (!t)460{461D1(printk("t1 stop!\n"));462}463464return IRQ_HANDLED;465}466467static void wake_up_func(unsigned long data)468{469wait_queue_head_t *sleep_wait_p = (wait_queue_head_t *)data;470wake_up(sleep_wait_p);471}472473474/* Useful API */475476void schedule_usleep(unsigned long us)477{478struct fast_timer t;479wait_queue_head_t sleep_wait;480init_waitqueue_head(&sleep_wait);481482D1(printk("schedule_usleep(%d)\n", us));483start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,484"usleep");485/* Uninterruptible sleep on the fast timer. (The condition is somewhat486* redundant since the timer is what wakes us up.) */487wait_event(sleep_wait, !fast_timer_pending(&t));488489D1(printk("done schedule_usleep(%d)\n", us));490}491492#ifdef CONFIG_PROC_FS493static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len494,int *eof, void *data_unused);495static struct proc_dir_entry *fasttimer_proc_entry;496#endif /* CONFIG_PROC_FS */497498#ifdef CONFIG_PROC_FS499500/* This value is very much based on testing */501#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)502503static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len504,int *eof, void *data_unused)505{506unsigned long flags;507int i = 0;508int num_to_show;509struct fasttime_t tv;510struct fast_timer *t, *nextt;511static char *bigbuf = NULL;512static unsigned long used;513514if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))515{516used = 0;517if (buf)518buf[0] = '\0';519return 0;520}521522if (!offset || !used)523{524do_gettimeofday_fast(&tv);525526used = 0;527used += sprintf(bigbuf + used, "Fast timers added: %i\n",528fast_timers_added);529used += sprintf(bigbuf + used, "Fast timers started: %i\n",530fast_timers_started);531used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",532fast_timer_ints);533used += sprintf(bigbuf + used, "Fast timers expired: %i\n",534fast_timers_expired);535used += sprintf(bigbuf + used, "Fast timers deleted: %i\n",536fast_timers_deleted);537used += sprintf(bigbuf + used, "Fast timer running: %s\n",538fast_timer_running ? "yes" : "no");539used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n",540(unsigned long)tv.tv_jiff,541(unsigned long)tv.tv_usec);542#ifdef FAST_TIMER_SANITY_CHECKS543used += sprintf(bigbuf + used, "Sanity failed: %i\n",544sanity_failed);545#endif546used += sprintf(bigbuf + used, "\n");547548#ifdef DEBUG_LOG_INCLUDED549{550int end_i = debug_log_cnt;551i = 0;552553if (debug_log_cnt_wrapped)554{555i = debug_log_cnt;556}557558while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&559used+100 < BIG_BUF_SIZE)560{561used += sprintf(bigbuf + used, debug_log_string[i],562debug_log_value[i]);563i = (i+1) % DEBUG_LOG_MAX;564}565}566used += sprintf(bigbuf + used, "\n");567#endif568569num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:570NUM_TIMER_STATS);571used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);572for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)573{574int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;575576#if 1 //ndef FAST_TIMER_LOG577used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"578"\n",579timer_div_settings[cur],580timer_freq_settings[cur],581timer_delay_settings[cur]582);583#endif584#ifdef FAST_TIMER_LOG585t = &timer_started_log[cur];586used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "587"d: %6li us data: 0x%08lX"588"\n",589t->name,590(unsigned long)t->tv_set.tv_jiff,591(unsigned long)t->tv_set.tv_usec,592(unsigned long)t->tv_expires.tv_jiff,593(unsigned long)t->tv_expires.tv_usec,594t->delay_us,595t->data596);597#endif598}599used += sprintf(bigbuf + used, "\n");600601#ifdef FAST_TIMER_LOG602num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:603NUM_TIMER_STATS);604used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);605for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)606{607t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];608used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "609"d: %6li us data: 0x%08lX"610"\n",611t->name,612(unsigned long)t->tv_set.tv_jiff,613(unsigned long)t->tv_set.tv_usec,614(unsigned long)t->tv_expires.tv_jiff,615(unsigned long)t->tv_expires.tv_usec,616t->delay_us,617t->data618);619}620used += sprintf(bigbuf + used, "\n");621622num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:623NUM_TIMER_STATS);624used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);625for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)626{627t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];628used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "629"d: %6li us data: 0x%08lX"630"\n",631t->name,632(unsigned long)t->tv_set.tv_jiff,633(unsigned long)t->tv_set.tv_usec,634(unsigned long)t->tv_expires.tv_jiff,635(unsigned long)t->tv_expires.tv_usec,636t->delay_us,637t->data638);639}640used += sprintf(bigbuf + used, "\n");641#endif642643used += sprintf(bigbuf + used, "Active timers:\n");644local_irq_save(flags);645t = fast_timer_list;646while (t != NULL && (used+100 < BIG_BUF_SIZE))647{648nextt = t->next;649local_irq_restore(flags);650used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "651"d: %6li us data: 0x%08lX"652/* " func: 0x%08lX" */653"\n",654t->name,655(unsigned long)t->tv_set.tv_jiff,656(unsigned long)t->tv_set.tv_usec,657(unsigned long)t->tv_expires.tv_jiff,658(unsigned long)t->tv_expires.tv_usec,659t->delay_us,660t->data661/* , t->function */662);663local_irq_save(flags);664if (t->next != nextt)665{666printk(KERN_WARNING "timer removed!\n");667}668t = nextt;669}670local_irq_restore(flags);671}672673if (used - offset < len)674{675len = used - offset;676}677678memcpy(buf, bigbuf + offset, len);679*start = buf;680*eof = 1;681682return len;683}684#endif /* PROC_FS */685686#ifdef FAST_TIMER_TEST687static volatile unsigned long i = 0;688static volatile int num_test_timeout = 0;689static struct fast_timer tr[10];690static int exp_num[10];691692static struct fasttime_t tv_exp[100];693694static void test_timeout(unsigned long data)695{696do_gettimeofday_fast(&tv_exp[data]);697exp_num[data] = num_test_timeout;698699num_test_timeout++;700}701702static void test_timeout1(unsigned long data)703{704do_gettimeofday_fast(&tv_exp[data]);705exp_num[data] = num_test_timeout;706if (data < 7)707{708start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");709i++;710}711num_test_timeout++;712}713714DP(715static char buf0[2000];716static char buf1[2000];717static char buf2[2000];718static char buf3[2000];719static char buf4[2000];720);721722static char buf5[6000];723static int j_u[1000];724725static void fast_timer_test(void)726{727int prev_num;728int j;729730struct fasttime_t tv, tv0, tv1, tv2;731732printk("fast_timer_test() start\n");733do_gettimeofday_fast(&tv);734735for (j = 0; j < 1000; j++)736{737j_u[j] = GET_JIFFIES_USEC();738}739for (j = 0; j < 100; j++)740{741do_gettimeofday_fast(&tv_exp[j]);742}743printk(KERN_DEBUG "fast_timer_test() %is %06i\n",744tv.tv_jiff, tv.tv_usec);745746for (j = 0; j < 1000; j++)747{748printk("%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]);749j += 4;750}751for (j = 0; j < 100; j++)752{753printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",754tv_exp[j].tv_jiff, tv_exp[j].tv_usec,755tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,756tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,757tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,758tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);759j += 4;760}761do_gettimeofday_fast(&tv0);762start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");763DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));764i++;765start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");766DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));767i++;768start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");769DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));770i++;771start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");772DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));773i++;774start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");775DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));776i++;777do_gettimeofday_fast(&tv1);778779proc_fasttimer_read(buf5, NULL, 0, 0, 0);780781prev_num = num_test_timeout;782while (num_test_timeout < i)783{784if (num_test_timeout != prev_num)785{786prev_num = num_test_timeout;787}788}789do_gettimeofday_fast(&tv2);790printk(KERN_DEBUG "Timers started %is %06i\n",791tv0.tv_jiff, tv0.tv_usec);792printk(KERN_DEBUG "Timers started at %is %06i\n",793tv1.tv_jiff, tv1.tv_usec);794printk(KERN_DEBUG "Timers done %is %06i\n",795tv2.tv_jiff, tv2.tv_usec);796DP(printk("buf0:\n");797printk(buf0);798printk("buf1:\n");799printk(buf1);800printk("buf2:\n");801printk(buf2);802printk("buf3:\n");803printk(buf3);804printk("buf4:\n");805printk(buf4);806);807printk("buf5:\n");808printk(buf5);809810printk("timers set:\n");811for(j = 0; j<i; j++)812{813struct fast_timer *t = &tr[j];814printk("%-10s set: %6is %06ius exp: %6is %06ius "815"data: 0x%08X func: 0x%08X\n",816t->name,817t->tv_set.tv_jiff,818t->tv_set.tv_usec,819t->tv_expires.tv_jiff,820t->tv_expires.tv_usec,821t->data,822t->function823);824825printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",826t->delay_us,827tv_exp[j].tv_jiff,828tv_exp[j].tv_usec,829exp_num[j],830(tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *8311000000 + tv_exp[j].tv_usec -832t->tv_expires.tv_usec);833}834proc_fasttimer_read(buf5, NULL, 0, 0, 0);835printk("buf5 after all done:\n");836printk(buf5);837printk("fast_timer_test() done\n");838}839#endif840841842int fast_timer_init(void)843{844/* For some reason, request_irq() hangs when called froom time_init() */845if (!fast_timer_is_init)846{847#if 0 && defined(FAST_TIMER_TEST)848int i;849#endif850851printk(KERN_INFO "fast_timer_init()\n");852853#if 0 && defined(FAST_TIMER_TEST)854for (i = 0; i <= TIMER0_DIV; i++)855{856/* We must be careful not to get overflow... */857printk("%3i %6u\n", i, timer0_value_us[i]);858}859#endif860#ifdef CONFIG_PROC_FS861if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))862fasttimer_proc_entry->read_proc = proc_fasttimer_read;863#endif /* PROC_FS */864if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0,865"fast timer int", NULL))866{867printk("err: timer1 irq\n");868}869fast_timer_is_init = 1;870#ifdef FAST_TIMER_TEST871printk("do test\n");872fast_timer_test();873#endif874}875return 0;876}877__initcall(fast_timer_init);878879880