summaryrefslogtreecommitdiff
path: root/ztdummy.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-09-15 20:21:02 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-09-15 20:21:02 +0000
commit1194ba17f8471a178912380b544cc833f4cf1cdd (patch)
tree4c2ba1f35bbf4422fc7eb4afa72e28122d23098c /ztdummy.c
parent7e7baddc41682abc4b4499c146da8071c9c8be6a (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.c79
1 files changed, 76 insertions, 3 deletions
diff --git a/ztdummy.c b/ztdummy.c
index 3fc6caf..d83bd1f 100644
--- a/ztdummy.c
+++ b/ztdummy.c
@@ -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