diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-09-15 20:21:02 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-09-15 20:21:02 +0000 |
commit | 1194ba17f8471a178912380b544cc833f4cf1cdd (patch) | |
tree | 4c2ba1f35bbf4422fc7eb4afa72e28122d23098c /ztdummy.c | |
parent | 7e7baddc41682abc4b4499c146da8071c9c8be6a (diff) |
Include support for high-resolution timers for linux >= 2.6.22 (#10314).
Changes from the patch:
* Only support kernels >= 2.6.22, as hrtimer_forward is only exported as
of that version.
* Adapted to my recent changes in ztdummy.c .
* Use ZAPTEL_TIME_NS instead of ZAPTEL_RATE
* Simplified ticks debug statement. Will only be used if debug=2 or
debug=3 .
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3038 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'ztdummy.c')
-rw-r--r-- | ztdummy.c | 79 |
1 files changed, 76 insertions, 3 deletions
@@ -8,6 +8,8 @@ * Unified by Mark Spencer <markster@digium.com> * Converted to use RTC on i386 by Tony Mountifield <tony@softins.co.uk> * + * Converted to use HighResTimers on i386 by Jeffery Palmer <jeff@triggerinc.com> + * * Copyright (C) 2002, Hermes Softlab * Copyright (C) 2004, Digium, Inc. * @@ -28,6 +30,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ + +/* + * To use the high resolution timers, in your kernel CONFIG_HIGH_RES_TIMERS + * needs to be enabled (Processor type and features -> High Resolution + * Timer Support), and optionally HPET (Processor type and features -> + * HPET Timer Support) provides a better clock source. + */ + #include <linux/version.h> #ifndef VERSION_CODE @@ -46,7 +56,12 @@ */ #if defined(__i386__) || defined(__x86_64__) #if LINUX_VERSION_CODE >= VERSION_CODE(2,6,13) +/* The symbol hrtimer_forward is only exported as of 2.6.22: */ +#if defined(CONFIG_HIGH_RES_TIMERS) && LINUX_VERSION_CODE >= VERSION_CODE(2,6,22) +#define USE_HIGHRESTIMER +#else #define USE_RTC +#endif #else #if 0 #define USE_RTC @@ -70,6 +85,9 @@ #include <asm/io.h> #endif #ifdef LINUX26 +#ifdef USE_HIGHRESTIMER +#include <linux/hrtimer.h> +#endif #ifdef USE_RTC #include <linux/rtc.h> #endif @@ -83,16 +101,19 @@ static struct ztdummy *ztd; static int debug = 0; #ifdef LINUX26 -#ifdef USE_RTC +#ifdef USE_HIGHRESTIMER +#define ZTDUMMY_TYPE "HRtimer" +struct hrtimer zaptimer; +#elif defined(USE_RTC) #define ZTDUMMY_TYPE "RTC" static int rtc_rate = 0; static int current_rate = 0; static int taskletpending = 0; static struct tasklet_struct ztd_tlet; static void ztd_tasklet(unsigned long data); -#else /* ifndef USE_RTC */ +#else /* Linux 2.6, but no RTC or HRTIMER used */ #define ZTDUMMY_TYPE "Linux26" -/* New 2.6 kernel timer stuff */ +/* 2.6 kernel timer stuff */ static struct timer_list timer; #endif #else @@ -121,6 +142,12 @@ extern uhci_t **uhci_devices; #define ZAPTEL_RATE 1000 /* zaptel ticks per second */ #define ZAPTEL_TIME (1000000 / ZAPTEL_RATE) /* zaptel tick time in us */ +#define ZAPTEL_TIME_NS (ZAPTEL_TIME * 1000) /* zaptel tick time in ns */ + +/* Different bits of the debug variable: */ +#define DEBUG_GENERAL (1 << 0) +#define DEBUG_TICKS (1 << 1) + #ifdef LINUX26 #ifdef USE_RTC @@ -165,6 +192,38 @@ static void ztdummy_rtc_interrupt(void *private_data) } spin_unlock_irqrestore(&ztd->rtclock, flags); } +#elif defined(USE_HIGHRESTIMER) +static enum hrtimer_restart ztdummy_hr_int(struct hrtimer *htmr) +{ + unsigned long overrun; + + /* Trigger Zaptel */ + zt_receive(&ztd->span); + zt_transmit(&ztd->span); + + /* Overrun should always return 1, since we are in the timer that + * expired. + * We should worry if overrun is 2 or more; then we really missed + * a tick */ + overrun = hrtimer_forward(&zaptimer, htmr->expires, + ktime_set(0, ZAPTEL_TIME_NS)); + if(overrun > 1) { + if(printk_ratelimit()) + printk(KERN_NOTICE "ztdummy: HRTimer missed %lu ticks\n", + overrun - 1); + } + + if(debug && DEBUG_TICKS) { + static int count = 0; + /* Printk every 5 seconds, good test to see if timer is + * running properly */ + if (count++ % 5000 == 0) + printk(KERN_DEBUG "ztdummy: 5000 ticks from hrtimer\n"); + } + + /* Always restart the timer */ + return HRTIMER_RESTART; +} #else /* use kernel system tick timer if PC architecture RTC is not available */ static void ztdummy_timer(unsigned long param) @@ -276,6 +335,17 @@ int init_module(void) update_rtc_rate(ztd); rtc_control(&ztd->rtc_task, RTC_PIE_ON, 0); tasklet_init(&ztd_tlet, ztd_tasklet, 0); +#elif defined(USE_HIGHRESTIMER) + printk("ztdummy: Trying to load High Resolution Timer\n"); + hrtimer_init(&zaptimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + printk("ztdummy: Initialized High Resolution Timer\n"); + + /* Set timer callback function */ + zaptimer.function = ztdummy_hr_int; + + printk("ztdummy: Starting High Resolution Timer\n"); + hrtimer_start(&zaptimer, ktime_set(0, ZAPTEL_TIME_NS), HRTIMER_MODE_REL); + printk("ztdummy: High Resolution Timer started, good to go\n"); #else init_timer(&timer); timer.function = ztdummy_timer; @@ -320,6 +390,9 @@ void cleanup_module(void) } rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0); rtc_unregister(&ztd->rtc_task); +#elif defined(USE_HIGHRESTIMER) + /* Stop high resolution timer */ + hrtimer_cancel(&zaptimer); #else del_timer(&timer); #endif |