diff options
author | Shaun Ruffell <sruffell@digium.com> | 2010-02-08 22:49:32 +0000 |
---|---|---|
committer | Shaun Ruffell <sruffell@digium.com> | 2010-02-08 22:49:32 +0000 |
commit | 79a483ebbe9f7702529240ef4958209e1e2f5ed0 (patch) | |
tree | 7aa554e74ca4bf83805d382073efc91967f27f6c | |
parent | f513583a07701753b68d9413eda5acea1edbb034 (diff) |
vpmadt032,wcte12xp: Use a timeout on the read/write commands and during load.
It is possible for poorly behaving hardware (and driver bugs) to lockup the
modprobe process by having it wait indefinitely for a command to complete that
never will. DAHDI-451.
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8003 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r-- | drivers/dahdi/voicebus/GpakCust.c | 15 | ||||
-rw-r--r-- | drivers/dahdi/voicebus/voicebus.c | 19 | ||||
-rw-r--r-- | drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c | 8 | ||||
-rw-r--r-- | drivers/dahdi/wcte12xp/base.c | 26 | ||||
-rw-r--r-- | include/dahdi/kernel.h | 26 |
5 files changed, 61 insertions, 33 deletions
diff --git a/drivers/dahdi/voicebus/GpakCust.c b/drivers/dahdi/voicebus/GpakCust.c index 9491818..cce3308 100644 --- a/drivers/dahdi/voicebus/GpakCust.c +++ b/drivers/dahdi/voicebus/GpakCust.c @@ -133,9 +133,18 @@ static int vpmadt032_getreg_full_return(struct vpmadt032 *vpm, int pagechange, u16 addr, u16 *outbuf, struct vpmadt032_cmd *cmd) { unsigned long flags; - int ret = -EIO; + unsigned long ret; BUG_ON(!cmd); - wait_for_completion(&cmd->complete); + + /* We'll wait for 200ms */ + ret = wait_for_completion_timeout(&cmd->complete, HZ/5); + if (unlikely(!ret)) { + spin_lock_irqsave(&vpm->list_lock, flags); + list_add_tail(&cmd->node, &vpm->free_cmds); + spin_unlock_irqrestore(&vpm->list_lock, flags); + return -EIO; + } + if (cmd->desc & __VPM150M_FIN) { *outbuf = cmd->data; cmd->desc = 0; @@ -146,7 +155,7 @@ static int vpmadt032_getreg_full_return(struct vpmadt032 *vpm, int pagechange, spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->free_cmds); spin_unlock_irqrestore(&vpm->list_lock, flags); - return ret; + return 0; } /* Read one of the registers on the VPMADT032 */ diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c index ffbe971..2646302 100644 --- a/drivers/dahdi/voicebus/voicebus.c +++ b/drivers/dahdi/voicebus/voicebus.c @@ -997,23 +997,6 @@ vb_clear_start_receive_bit(struct voicebus *vb) VBUNLOCK(vb); } -static unsigned long -vb_wait_for_completion_timeout(struct completion *x, unsigned long timeout) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) - /* There is a race condition here. If x->done is reset to 0 - * before the call to wait_for_completion after this thread wakes. - */ - timeout = wait_event_timeout(x->wait, x->done, timeout); - if (timeout) - wait_for_completion(x); - - return timeout; -#else - return wait_for_completion_timeout(x, timeout); -#endif -} - /*! * \brief Stops the VoiceBus interface. * @@ -1036,7 +1019,7 @@ voicebus_stop(struct voicebus *vb) set_bit(STOP, &vb->flags); vb_clear_start_transmit_bit(vb); vb_clear_start_receive_bit(vb); - if (vb_wait_for_completion_timeout(&vb->stopped_completion, HZ)) { + if (wait_for_completion_timeout(&vb->stopped_completion, HZ)) { BUG_ON(!vb_is_stopped(vb)); } else { dev_warn(&vb->pdev->dev, "Timeout while waiting for board to " diff --git a/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c b/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c index d64931f..2aa15e9 100644 --- a/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c +++ b/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c @@ -116,13 +116,17 @@ static int vpmadt032_load_firmware(struct voicebus *vb) pci_set_drvdata(vb->pdev, ctx); old = vb->ops; vb->ops = &loader_operations; - wait_for_completion(&ctx->done); + if (wait_for_completion_timeout(&ctx->done, HZ*2)) { + dev_err(&vb->pdev->dev, + "Timeout waiting for load in %s.\n", __func__); + ret = -EIO; + } vb->ops = old; pci_set_drvdata(vb->pdev, old_drvdata); __vpmadt032_cleanup(ctx->pvt); error_exit: kfree(ctx); - return 0; + return ret; } static struct vpmadt_loader loader = { diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c index 43b5f5f..50aafd4 100644 --- a/drivers/dahdi/wcte12xp/base.c +++ b/drivers/dahdi/wcte12xp/base.c @@ -559,7 +559,7 @@ static inline int t1_setreg(struct t1 *wc, int addr, int val) static int t1_getreg(struct t1 *wc, int addr) { struct command *cmd = NULL; - int ret; + unsigned long ret; might_sleep(); @@ -570,7 +570,15 @@ static int t1_getreg(struct t1 *wc, int addr) cmd->data = 0x00; cmd->flags = __CMD_RD; submit_cmd(wc, cmd); - wait_for_completion(&cmd->complete); + ret = wait_for_completion_timeout(&cmd->complete, HZ/5); + if (unlikely(ret)) { + if (printk_ratelimit()) { + dev_warn(&wc->vb.pdev->dev, + "Timeout in %s\n", __func__); + } + free_cmd(wc, cmd); + return -EIO; + } ret = cmd->data; free_cmd(wc, cmd); return ret; @@ -592,8 +600,8 @@ static void t1_setleds(struct t1 *wc, int leds) static inline int t1_getpins(struct t1 *wc, int inisr) { - int ret = 0; struct command *cmd; + unsigned long ret; cmd = get_free_cmd(wc); BUG_ON(!cmd); @@ -602,10 +610,18 @@ static inline int t1_getpins(struct t1 *wc, int inisr) cmd->data = 0x00; cmd->flags = __CMD_PINS; submit_cmd(wc, cmd); - wait_for_completion(&cmd->complete); + ret = wait_for_completion_timeout(&cmd->complete, HZ/5); + if (unlikely(ret)) { + if (printk_ratelimit()) { + dev_warn(&wc->vb.pdev->dev, + "Timeout in %s\n", __func__); + } + free_cmd(wc, cmd); + return -EIO; + } ret = cmd->data; free_cmd(wc, cmd); - return ret; + return 0; } static void __t1xxp_set_clear(struct t1 *wc, int channo) diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h index 129e9b4..96c4076 100644 --- a/include/dahdi/kernel.h +++ b/include/dahdi/kernel.h @@ -1174,10 +1174,8 @@ static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss) /*! Maximum audio mask */ #define DAHDI_FORMAT_AUDIO_MASK ((1 << 16) - 1) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) -#define kzalloc(a, b) kcalloc(1, a, b) -#endif - +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) +#define KERN_CONT "" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) static inline void list_replace(struct list_head *old, struct list_head *new) { @@ -1186,7 +1184,25 @@ static inline void list_replace(struct list_head *old, struct list_head *new) new->prev = old->prev; new->prev->next = new; } -#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) +#define kzalloc(a, b) kcalloc(1, a, b) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) +static inline unsigned long +wait_for_completion_timeout(struct completion *x, unsigned long timeout) +{ + /* There is a race condition here. If x->done is reset to 0 + * before the call to wait_for_completion after this thread wakes. + */ + timeout = wait_event_timeout(x->wait, x->done, timeout); + if (timeout) + wait_for_completion(x); + + return timeout; +} +#endif /* 2.6.11 */ +#endif /* 2.6.14 */ +#endif /* 2.6.18 */ +#endif /* 2.6.31 */ #ifndef DMA_BIT_MASK #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) |