summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-02-08 22:49:32 +0000
committerShaun Ruffell <sruffell@digium.com>2010-02-08 22:49:32 +0000
commit42e275be0f7ce08a9fe2adf4815f7fd926a341bb (patch)
tree7aa554e74ca4bf83805d382073efc91967f27f6c
parent791a3df5afe66a8cbe15ebe030c2956fd2e00818 (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.c15
-rw-r--r--drivers/dahdi/voicebus/voicebus.c19
-rw-r--r--drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c8
-rw-r--r--drivers/dahdi/wcte12xp/base.c26
-rw-r--r--include/dahdi/kernel.h26
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))