Path: blob/master/arch/cris/arch-v32/kernel/fasttimer.c
15125 views
/*1* linux/arch/cris/kernel/fasttimer.c2*3* Fast timers for ETRAX FS4*5* Copyright (C) 2000-2006 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/vmalloc.h>14#include <linux/interrupt.h>15#include <linux/time.h>16#include <linux/delay.h>1718#include <asm/irq.h>19#include <asm/system.h>2021#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>2627/*28* timer0 is running at 100MHz and generating jiffies timer ticks29* at 100 or 1000 HZ.30* fasttimer gives an API that gives timers that expire "between" the jiffies31* giving microsecond resolution (10 ns).32* fasttimer uses reg_timer_rw_trig register to get interrupt when33* r_time reaches a certain value.34*/353637#define DEBUG_LOG_INCLUDED38#define FAST_TIMER_LOG39/* #define FAST_TIMER_TEST */4041#define FAST_TIMER_SANITY_CHECKS4243#ifdef FAST_TIMER_SANITY_CHECKS44static int sanity_failed;45#endif4647#define D1(x)48#define D2(x)49#define DP(x)5051static unsigned int fast_timer_running;52static unsigned int fast_timers_added;53static unsigned int fast_timers_started;54static unsigned int fast_timers_expired;55static unsigned int fast_timers_deleted;56static unsigned int fast_timer_is_init;57static unsigned int fast_timer_ints;5859struct fast_timer *fast_timer_list = NULL;6061#ifdef DEBUG_LOG_INCLUDED62#define DEBUG_LOG_MAX 12863static const char * debug_log_string[DEBUG_LOG_MAX];64static unsigned long debug_log_value[DEBUG_LOG_MAX];65static unsigned int debug_log_cnt;66static unsigned int debug_log_cnt_wrapped;6768#define DEBUG_LOG(string, value) \69{ \70unsigned long log_flags; \71local_irq_save(log_flags); \72debug_log_string[debug_log_cnt] = (string); \73debug_log_value[debug_log_cnt] = (unsigned long)(value); \74if (++debug_log_cnt >= DEBUG_LOG_MAX) \75{ \76debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \77debug_log_cnt_wrapped = 1; \78} \79local_irq_restore(log_flags); \80}81#else82#define DEBUG_LOG(string, value)83#endif848586#define NUM_TIMER_STATS 1687#ifdef FAST_TIMER_LOG88struct fast_timer timer_added_log[NUM_TIMER_STATS];89struct fast_timer timer_started_log[NUM_TIMER_STATS];90struct fast_timer timer_expired_log[NUM_TIMER_STATS];91#endif9293int timer_div_settings[NUM_TIMER_STATS];94int timer_delay_settings[NUM_TIMER_STATS];9596struct work_struct fast_work;9798static void99timer_trig_handler(struct work_struct *work);100101102103/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */104inline void do_gettimeofday_fast(struct fasttime_t *tv)105{106tv->tv_jiff = jiffies;107tv->tv_usec = GET_JIFFIES_USEC();108}109110inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)111{112/* Compare jiffies. Takes care of wrapping */113if (time_before(t0->tv_jiff, t1->tv_jiff))114return -1;115else if (time_after(t0->tv_jiff, t1->tv_jiff))116return 1;117118/* Compare us */119if (t0->tv_usec < t1->tv_usec)120return -1;121else if (t0->tv_usec > t1->tv_usec)122return 1;123return 0;124}125126/* Called with ints off */127inline void start_timer_trig(unsigned long delay_us)128{129reg_timer_rw_ack_intr ack_intr = { 0 };130reg_timer_rw_intr_mask intr_mask;131reg_timer_rw_trig trig;132reg_timer_rw_trig_cfg trig_cfg = { 0 };133reg_timer_r_time r_time0;134reg_timer_r_time r_time1;135unsigned char trig_wrap;136unsigned char time_wrap;137138r_time0 = REG_RD(timer, regi_timer0, r_time);139140D1(printk("start_timer_trig : %d us freq: %i div: %i\n",141delay_us, freq_index, div));142/* Clear trig irq */143intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);144intr_mask.trig = 0;145REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);146147/* Set timer values and check if trigger wraps. */148/* r_time is 100MHz (10 ns resolution) */149trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;150151timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;152timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;153154/* Ack interrupt */155ack_intr.trig = 1;156REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);157158/* Start timer */159REG_WR(timer, regi_timer0, rw_trig, trig);160trig_cfg.tmr = regk_timer_time;161REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);162163/* Check if we have already passed the trig time */164r_time1 = REG_RD(timer, regi_timer0, r_time);165time_wrap = r_time1 < r_time0;166167if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {168/* No, Enable trig irq */169intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);170intr_mask.trig = 1;171REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);172fast_timers_started++;173fast_timer_running = 1;174} else {175/* We have passed the time, disable trig point, ack intr */176trig_cfg.tmr = regk_timer_off;177REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);178REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);179/* call the int routine */180INIT_WORK(&fast_work, timer_trig_handler);181schedule_work(&fast_work);182}183184}185186/* In version 1.4 this function takes 27 - 50 us */187void start_one_shot_timer(struct fast_timer *t,188fast_timer_function_type *function,189unsigned long data,190unsigned long delay_us,191const char *name)192{193unsigned long flags;194struct fast_timer *tmp;195196D1(printk("sft %s %d us\n", name, delay_us));197198local_irq_save(flags);199200do_gettimeofday_fast(&t->tv_set);201tmp = fast_timer_list;202203#ifdef FAST_TIMER_SANITY_CHECKS204/* Check so this is not in the list already... */205while (tmp != NULL) {206if (tmp == t) {207printk(KERN_DEBUG208"timer name: %s data: 0x%08lX already "209"in list!\n", name, data);210sanity_failed++;211goto done;212} else213tmp = tmp->next;214}215tmp = fast_timer_list;216#endif217218t->delay_us = delay_us;219t->function = function;220t->data = data;221t->name = name;222223t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;224t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;225if (t->tv_expires.tv_usec > 1000000) {226t->tv_expires.tv_usec -= 1000000;227t->tv_expires.tv_jiff += HZ;228}229#ifdef FAST_TIMER_LOG230timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;231#endif232fast_timers_added++;233234/* Check if this should timeout before anything else */235if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) {236/* Put first in list and modify the timer value */237t->prev = NULL;238t->next = fast_timer_list;239if (fast_timer_list)240fast_timer_list->prev = t;241fast_timer_list = t;242#ifdef FAST_TIMER_LOG243timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;244#endif245start_timer_trig(delay_us);246} else {247/* Put in correct place in list */248while (tmp->next &&249fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)250tmp = tmp->next;251/* Insert t after tmp */252t->prev = tmp;253t->next = tmp->next;254if (tmp->next)255{256tmp->next->prev = t;257}258tmp->next = t;259}260261D2(printk("start_one_shot_timer: %d us done\n", delay_us));262263done:264local_irq_restore(flags);265} /* start_one_shot_timer */266267static inline int fast_timer_pending (const struct fast_timer * t)268{269return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);270}271272static inline int detach_fast_timer (struct fast_timer *t)273{274struct fast_timer *next, *prev;275if (!fast_timer_pending(t))276return 0;277next = t->next;278prev = t->prev;279if (next)280next->prev = prev;281if (prev)282prev->next = next;283else284fast_timer_list = next;285fast_timers_deleted++;286return 1;287}288289int del_fast_timer(struct fast_timer * t)290{291unsigned long flags;292int ret;293294local_irq_save(flags);295ret = detach_fast_timer(t);296t->next = t->prev = NULL;297local_irq_restore(flags);298return ret;299} /* del_fast_timer */300301302/* Interrupt routines or functions called in interrupt context */303304/* Timer interrupt handler for trig interrupts */305306static irqreturn_t307timer_trig_interrupt(int irq, void *dev_id)308{309reg_timer_r_masked_intr masked_intr;310/* Check if the timer interrupt is for us (a trig int) */311masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);312if (!masked_intr.trig)313return IRQ_NONE;314timer_trig_handler(NULL);315return IRQ_HANDLED;316}317318static void timer_trig_handler(struct work_struct *work)319{320reg_timer_rw_ack_intr ack_intr = { 0 };321reg_timer_rw_intr_mask intr_mask;322reg_timer_rw_trig_cfg trig_cfg = { 0 };323struct fast_timer *t;324unsigned long flags;325326/* We keep interrupts disabled not only when we modify the327* fast timer list, but any time we hold a reference to a328* timer in the list, since del_fast_timer may be called329* from (another) interrupt context. Thus, the only time330* when interrupts are enabled is when calling the timer331* callback function.332*/333local_irq_save(flags);334335/* Clear timer trig interrupt */336intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);337intr_mask.trig = 0;338REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);339340/* First stop timer, then ack interrupt */341/* Stop timer */342trig_cfg.tmr = regk_timer_off;343REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);344345/* Ack interrupt */346ack_intr.trig = 1;347REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);348349fast_timer_running = 0;350fast_timer_ints++;351352fast_timer_function_type *f;353unsigned long d;354355t = fast_timer_list;356while (t) {357struct fasttime_t tv;358359/* Has it really expired? */360do_gettimeofday_fast(&tv);361D1(printk(KERN_DEBUG362"t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));363364if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {365/* Yes it has expired */366#ifdef FAST_TIMER_LOG367timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;368#endif369fast_timers_expired++;370371/* Remove this timer before call, since it may reuse the timer */372if (t->prev)373t->prev->next = t->next;374else375fast_timer_list = t->next;376if (t->next)377t->next->prev = t->prev;378t->prev = NULL;379t->next = NULL;380381/* Save function callback data before enabling382* interrupts, since the timer may be removed and we383* don't know how it was allocated (e.g. ->function384* and ->data may become overwritten after deletion385* if the timer was stack-allocated).386*/387f = t->function;388d = t->data;389390if (f != NULL) {391/* Run the callback function with interrupts392* enabled. */393local_irq_restore(flags);394f(d);395local_irq_save(flags);396} else397DEBUG_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 */400D1(printk(".\n"));401}402403t = fast_timer_list;404if (t != NULL) {405/* Start next timer.. */406long us = 0;407struct fasttime_t tv;408409do_gettimeofday_fast(&tv);410411/* time_after_eq takes care of wrapping */412if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))413us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *4141000000 / HZ + t->tv_expires.tv_usec -415tv.tv_usec);416417if (us > 0) {418if (!fast_timer_running) {419#ifdef FAST_TIMER_LOG420timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;421#endif422start_timer_trig(us);423}424break;425} else {426/* Timer already expired, let's handle it better late than never.427* The normal loop handles it428*/429D1(printk("e! %d\n", us));430}431}432}433434local_irq_restore(flags);435436if (!t)437D1(printk("ttrig stop!\n"));438}439440static void wake_up_func(unsigned long data)441{442wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data;443wake_up(sleep_wait_p);444}445446447/* Useful API */448449void schedule_usleep(unsigned long us)450{451struct fast_timer t;452wait_queue_head_t sleep_wait;453init_waitqueue_head(&sleep_wait);454455D1(printk("schedule_usleep(%d)\n", us));456start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,457"usleep");458/* Uninterruptible sleep on the fast timer. (The condition is459* somewhat redundant since the timer is what wakes us up.) */460wait_event(sleep_wait, !fast_timer_pending(&t));461462D1(printk("done schedule_usleep(%d)\n", us));463}464465#ifdef CONFIG_PROC_FS466static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len467,int *eof, void *data_unused);468static struct proc_dir_entry *fasttimer_proc_entry;469#endif /* CONFIG_PROC_FS */470471#ifdef CONFIG_PROC_FS472473/* This value is very much based on testing */474#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)475476static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len477,int *eof, void *data_unused)478{479unsigned long flags;480int i = 0;481int num_to_show;482struct fasttime_t tv;483struct fast_timer *t, *nextt;484static char *bigbuf = NULL;485static unsigned long used;486487if (!bigbuf) {488bigbuf = vmalloc(BIG_BUF_SIZE);489if (!bigbuf) {490used = 0;491if (buf)492buf[0] = '\0';493return 0;494}495}496497if (!offset || !used) {498do_gettimeofday_fast(&tv);499500used = 0;501used += sprintf(bigbuf + used, "Fast timers added: %i\n",502fast_timers_added);503used += sprintf(bigbuf + used, "Fast timers started: %i\n",504fast_timers_started);505used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",506fast_timer_ints);507used += sprintf(bigbuf + used, "Fast timers expired: %i\n",508fast_timers_expired);509used += sprintf(bigbuf + used, "Fast timers deleted: %i\n",510fast_timers_deleted);511used += sprintf(bigbuf + used, "Fast timer running: %s\n",512fast_timer_running ? "yes" : "no");513used += 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_CHECKS517used += sprintf(bigbuf + used, "Sanity failed: %i\n",518sanity_failed);519#endif520used += sprintf(bigbuf + used, "\n");521522#ifdef DEBUG_LOG_INCLUDED523{524int end_i = debug_log_cnt;525i = 0;526527if (debug_log_cnt_wrapped)528i = debug_log_cnt;529530while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&531used+100 < BIG_BUF_SIZE)532{533used += sprintf(bigbuf + used, debug_log_string[i],534debug_log_value[i]);535i = (i+1) % DEBUG_LOG_MAX;536}537}538used += sprintf(bigbuf + used, "\n");539#endif540541num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:542NUM_TIMER_STATS);543used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);544for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)545{546int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;547548#if 1 //ndef FAST_TIMER_LOG549used += sprintf(bigbuf + used, "div: %i delay: %i"550"\n",551timer_div_settings[cur],552timer_delay_settings[cur]553);554#endif555#ifdef FAST_TIMER_LOG556t = &timer_started_log[cur];557used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "558"d: %6li us data: 0x%08lX"559"\n",560t->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,565t->delay_us,566t->data567);568#endif569}570used += sprintf(bigbuf + used, "\n");571572#ifdef FAST_TIMER_LOG573num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:574NUM_TIMER_STATS);575used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);576for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)577{578t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];579used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "580"d: %6li us data: 0x%08lX"581"\n",582t->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,587t->delay_us,588t->data589);590}591used += sprintf(bigbuf + used, "\n");592593num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:594NUM_TIMER_STATS);595used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);596for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)597{598t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];599used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "600"d: %6li us data: 0x%08lX"601"\n",602t->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,607t->delay_us,608t->data609);610}611used += sprintf(bigbuf + used, "\n");612#endif613614used += sprintf(bigbuf + used, "Active timers:\n");615local_irq_save(flags);616t = fast_timer_list;617while (t != NULL && (used+100 < BIG_BUF_SIZE))618{619nextt = t->next;620local_irq_restore(flags);621used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "622"d: %6li us data: 0x%08lX"623/* " func: 0x%08lX" */624"\n",625t->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,630t->delay_us,631t->data632/* , t->function */633);634local_irq_save(flags);635if (t->next != nextt)636{637printk("timer removed!\n");638}639t = nextt;640}641local_irq_restore(flags);642}643644if (used - offset < len)645{646len = used - offset;647}648649memcpy(buf, bigbuf + offset, len);650*start = buf;651*eof = 1;652653return len;654}655#endif /* PROC_FS */656657#ifdef FAST_TIMER_TEST658static volatile unsigned long i = 0;659static volatile int num_test_timeout = 0;660static struct fast_timer tr[10];661static int exp_num[10];662663static struct fasttime_t tv_exp[100];664665static void test_timeout(unsigned long data)666{667do_gettimeofday_fast(&tv_exp[data]);668exp_num[data] = num_test_timeout;669670num_test_timeout++;671}672673static void test_timeout1(unsigned long data)674{675do_gettimeofday_fast(&tv_exp[data]);676exp_num[data] = num_test_timeout;677if (data < 7)678{679start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");680i++;681}682num_test_timeout++;683}684685DP(686static char buf0[2000];687static char buf1[2000];688static char buf2[2000];689static char buf3[2000];690static char buf4[2000];691);692693static char buf5[6000];694static int j_u[1000];695696static void fast_timer_test(void)697{698int prev_num;699int j;700701struct fasttime_t tv, tv0, tv1, tv2;702703printk("fast_timer_test() start\n");704do_gettimeofday_fast(&tv);705706for (j = 0; j < 1000; j++)707{708j_u[j] = GET_JIFFIES_USEC();709}710for (j = 0; j < 100; j++)711{712do_gettimeofday_fast(&tv_exp[j]);713}714printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec);715716for (j = 0; j < 1000; j++)717{718printk(KERN_DEBUG "%i %i %i %i %i\n",719j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);720j += 4;721}722for (j = 0; j < 100; j++)723{724printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",725tv_exp[j].tv_jiff, tv_exp[j].tv_usec,726tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,727tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,728tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,729tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);730j += 4;731}732do_gettimeofday_fast(&tv0);733start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");734DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));735i++;736start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");737DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));738i++;739start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");740DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));741i++;742start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");743DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));744i++;745start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");746DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));747i++;748do_gettimeofday_fast(&tv1);749750proc_fasttimer_read(buf5, NULL, 0, 0, 0);751752prev_num = num_test_timeout;753while (num_test_timeout < i)754{755if (num_test_timeout != prev_num)756prev_num = num_test_timeout;757}758do_gettimeofday_fast(&tv2);759printk(KERN_INFO "Timers started %is %06i\n",760tv0.tv_jiff, tv0.tv_usec);761printk(KERN_INFO "Timers started at %is %06i\n",762tv1.tv_jiff, tv1.tv_usec);763printk(KERN_INFO "Timers done %is %06i\n",764tv2.tv_jiff, tv2.tv_usec);765DP(printk("buf0:\n");766printk(buf0);767printk("buf1:\n");768printk(buf1);769printk("buf2:\n");770printk(buf2);771printk("buf3:\n");772printk(buf3);773printk("buf4:\n");774printk(buf4);775);776printk("buf5:\n");777printk(buf5);778779printk("timers set:\n");780for(j = 0; j<i; j++)781{782struct fast_timer *t = &tr[j];783printk("%-10s set: %6is %06ius exp: %6is %06ius "784"data: 0x%08X func: 0x%08X\n",785t->name,786t->tv_set.tv_jiff,787t->tv_set.tv_usec,788t->tv_expires.tv_jiff,789t->tv_expires.tv_usec,790t->data,791t->function792);793794printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",795t->delay_us,796tv_exp[j].tv_jiff,797tv_exp[j].tv_usec,798exp_num[j],799(tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *8001000000 + tv_exp[j].tv_usec -801t->tv_expires.tv_usec);802}803proc_fasttimer_read(buf5, NULL, 0, 0, 0);804printk("buf5 after all done:\n");805printk(buf5);806printk("fast_timer_test() done\n");807}808#endif809810811int fast_timer_init(void)812{813/* For some reason, request_irq() hangs when called froom time_init() */814if (!fast_timer_is_init)815{816printk("fast_timer_init()\n");817818#ifdef CONFIG_PROC_FS819fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0);820if (fasttimer_proc_entry)821fasttimer_proc_entry->read_proc = proc_fasttimer_read;822#endif /* PROC_FS */823if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,824IRQF_SHARED | IRQF_DISABLED,825"fast timer int", &fast_timer_list))826printk(KERN_ERR "err: fasttimer irq\n");827fast_timer_is_init = 1;828#ifdef FAST_TIMER_TEST829printk("do test\n");830fast_timer_test();831#endif832}833return 0;834}835__initcall(fast_timer_init);836837838