diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2003-05-15 01:30:02 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2003-05-15 01:30:02 +0000 |
commit | 5b864019c5aeccf32d5ab83a856360e46e1436d9 (patch) | |
tree | 8180720fcf1be92ca1f006be535baed4f3b75861 | |
parent | 58d72a7794acc5d64a4d0580fca22aae04c149ca (diff) |
Initial "watchdog" support
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@180 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-x | Makefile | 5 | ||||
-rwxr-xr-x | wcfxs.c | 11 | ||||
-rwxr-xr-x | wctdm.c | 11 | ||||
-rwxr-xr-x | zaptel.c | 62 | ||||
-rwxr-xr-x | zaptel.h | 17 |
5 files changed, 92 insertions, 14 deletions
@@ -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) @@ -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) @@ -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) @@ -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); @@ -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]; |