summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMakefile5
-rwxr-xr-xwcfxs.c11
-rwxr-xr-xwctdm.c11
-rwxr-xr-xzaptel.c62
-rwxr-xr-xzaptel.h17
5 files changed, 92 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index dfeb22c..28af362 100755
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,11 @@ KFLAGS+=-DECHO_CAN_MARK2
#
KFLAGS+=-DCONFIG_ZAPATA_PPP
#
+# Uncomment to enable "watchdog" to monitor if interfaces
+# stop taking interrupts or otherwise misbehave
+#
+#KFLAGS+=-DCONFIG_ZAPTEL_WATCHDOG
+#
# ISA Defaults can be set here.
#
KFLAGS+=-DTORMENTA_BASE=$(BASEADDR)
diff --git a/wcfxs.c b/wcfxs.c
index 9e0ff1e..6ecf724 100755
--- a/wcfxs.c
+++ b/wcfxs.c
@@ -256,10 +256,9 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
if (ints & 0x10) {
- /* Restart DMA */
- printk("PCI Master abort\n");
+ /* Stop DMA, wait for watchdog */
+ printk("FXS PCI Master abort\n");
wcfxs_stop_dma(wc);
- wcfxs_restart_dma(wc);
return;
}
@@ -1073,10 +1072,6 @@ static void wcfxs_restart_dma(struct wcfxs *wc)
{
int x;
/* Reset Master and TDM */
- outb(0x0f, wc->ioaddr + WC_CNTL);
- /* Can't really wait, so simulate a wait */
- for (x=0;x<100;x++)
- inb(wc->ioaddr + WC_CNTL);
outb(0x01, wc->ioaddr + WC_CNTL);
outb(0x01, wc->ioaddr + WC_OPER);
}
@@ -1084,6 +1079,8 @@ static void wcfxs_restart_dma(struct wcfxs *wc)
static void wcfxs_stop_dma(struct wcfxs *wc)
{
outb(0x00, wc->ioaddr + WC_OPER);
+ /* Reset TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
}
static void wcfxs_disable_interrupts(struct wcfxs *wc)
diff --git a/wctdm.c b/wctdm.c
index 9e0ff1e..6ecf724 100755
--- a/wctdm.c
+++ b/wctdm.c
@@ -256,10 +256,9 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
if (ints & 0x10) {
- /* Restart DMA */
- printk("PCI Master abort\n");
+ /* Stop DMA, wait for watchdog */
+ printk("FXS PCI Master abort\n");
wcfxs_stop_dma(wc);
- wcfxs_restart_dma(wc);
return;
}
@@ -1073,10 +1072,6 @@ static void wcfxs_restart_dma(struct wcfxs *wc)
{
int x;
/* Reset Master and TDM */
- outb(0x0f, wc->ioaddr + WC_CNTL);
- /* Can't really wait, so simulate a wait */
- for (x=0;x<100;x++)
- inb(wc->ioaddr + WC_CNTL);
outb(0x01, wc->ioaddr + WC_CNTL);
outb(0x01, wc->ioaddr + WC_OPER);
}
@@ -1084,6 +1079,8 @@ static void wcfxs_restart_dma(struct wcfxs *wc)
static void wcfxs_stop_dma(struct wcfxs *wc)
{
outb(0x00, wc->ioaddr + WC_OPER);
+ /* Reset TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
}
static void wcfxs_disable_interrupts(struct wcfxs *wc)
diff --git a/zaptel.c b/zaptel.c
index df3615d..c2a073a 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -5401,6 +5401,9 @@ int zt_receive(struct zt_span *span)
unsigned long flags;
#if 1
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ span->watchcounter--;
+#endif
for (x=0;x<span->channels;x++) {
if (span->chans[x].master == &span->chans[x]) {
spin_lock_irqsave(&span->chans[x].lock, flags);
@@ -5553,6 +5556,59 @@ static struct file_operations zt_fops = {
fasync: NULL,
};
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+static struct timer_list watchdogtimer;
+
+static void watchdog_check(unsigned long ignored)
+{
+ int x;
+ long flags;
+ local_irq_save(flags);
+ for (x=0;x<maxspans;x++) {
+ if (spans[x]) {
+ if (spans[x]->watchcounter == ZT_WATCHDOG_INIT) {
+ /* Whoops, dead card */
+ if ((spans[x]->watchstate == ZT_WATCHSTATE_OK) ||
+ (spans[x]->watchstate == ZT_WATCHSTATE_UNKNOWN)) {
+ spans[x]->watchstate = ZT_WATCHSTATE_RECOVERING;
+ if (spans[x]->watchdog) {
+ printk("Kicking span %s\n", spans[x]->name);
+ spans[x]->watchdog(spans[x], ZT_WATCHDOG_NOINTS);
+ } else {
+ printk("Span %s is dead with no revival\n", spans[x]->name);
+ spans[x]->watchstate = ZT_WATCHSTATE_FAILED;
+ }
+ }
+ } else {
+ if (spans[x]->watchstate != ZT_WATCHSTATE_OK)
+ printk("Span %s is alive!\n", spans[x]->name);
+ spans[x]->watchstate = ZT_WATCHSTATE_OK;
+ }
+ spans[x]->watchcounter = ZT_WATCHDOG_INIT;
+ }
+ }
+ local_irq_restore(flags);
+ mod_timer(&watchdogtimer, jiffies + 1);
+}
+
+static int __init watchdog_init(void)
+{
+ init_timer(&watchdogtimer);
+ watchdogtimer.expires = 0;
+ watchdogtimer.data =0;
+ watchdogtimer.function = watchdog_check;
+ /* Run every couple of jiffy or so */
+ mod_timer(&watchdogtimer, jiffies + 1);
+ return 0;
+}
+
+static void watchdog_cleanup(void)
+{
+ del_timer(&watchdogtimer);
+}
+
+#endif
+
static int __init zt_init(void) {
int res = 0;
@@ -5582,6 +5638,9 @@ static int __init zt_init(void) {
fasthdlc_precalc();
rotate_sums();
rwlock_init(&chan_lock);
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ watchdog_init();
+#endif
return res;
}
@@ -5605,6 +5664,9 @@ static void __exit zt_cleanup(void) {
#else
unregister_chrdev(ZT_MAJOR, "zaptel");
#endif
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ watchdog_cleanup();
+#endif
}
module_init(zt_init);
diff --git a/zaptel.h b/zaptel.h
index b91573a..a7a0ff2 100755
--- a/zaptel.h
+++ b/zaptel.h
@@ -1161,8 +1161,25 @@ struct zt_span {
#ifdef CONFIG_DEVFS_FS
devfs_handle_t dhandle; /* Directory name */
#endif
+ /* If the watchdog detects no received data, it will call the
+ watchdog routine */
+ int (*watchdog)(struct zt_span *span, int cause);
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ int watchcounter;
+ int watchstate;
+#endif
};
+#define ZT_WATCHDOG_NOINTS (1 << 0)
+
+#define ZT_WATCHDOG_INIT 1000
+
+#define ZT_WATCHSTATE_UNKNOWN 0
+#define ZT_WATCHSTATE_OK 1
+#define ZT_WATCHSTATE_RECOVERING 2
+#define ZT_WATCHSTATE_FAILED 3
+
+
struct zt_dynamic_driver {
/* Driver name (e.g. Eth) */
char name[20];