diff options
author | Andy Walls <awalls@radix.net> | 2009-04-14 01:53:09 (GMT) |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-16 21:20:44 (GMT) |
commit | 5f0a3cfcfd315d87de8f80af49b114daf7137823 (patch) | |
tree | f5424f63daca454c4c02d2d267f3d080c262d04b | |
parent | 87116159517ecf6b9cf62a136f2935a63833c485 (diff) | |
download | linux-5f0a3cfcfd315d87de8f80af49b114daf7137823.tar.xz |
V4L/DVB (11617): cx18: Set up to wait for a one-shot response before sending a firmware cmd
When sending an outgoing firmware command, prepare to wait before we raise the
interrupt, so we don't miss the wake_up() on the acknowledgment. When waiting
for the acknowledgement, there is no need to loop around schedule(), as there
will only be one interrupt, and hence one wake_up(), issued.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 2a4d435..df7d61d 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -478,9 +478,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) u32 __iomem *xpu_state; wait_queue_head_t *waitq; struct mutex *mb_lock; - long int timeout, ret; + unsigned long int t0, timeout, ret; int i; char argstr[MAX_MB_ARGUMENTS*11+1]; + DEFINE_WAIT(w); if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); @@ -562,25 +563,49 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", irq, info->name); + + /* So we don't miss the wakeup, prepare to wait before notifying fw */ + prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - ret = wait_event_timeout( - *waitq, - cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), - timeout); + t0 = jiffies; + ack = cx18_readl(cx, &mb->ack); + if (ack != req) { + schedule_timeout(timeout); + ret = jiffies - t0; + ack = cx18_readl(cx, &mb->ack); + } else { + ret = jiffies - t0; + } + + finish_wait(waitq, &w); - if (ret == 0) { - /* Timed out */ + if (req != ack) { mutex_unlock(mb_lock); - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU " - "acknowledgement\n", - info->name, jiffies_to_msecs(timeout)); + if (ret >= timeout) { + /* Timed out */ + CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " + "for RPU acknowledgement\n", + info->name, jiffies_to_msecs(ret)); + } else { + CX18_DEBUG_WARN("woken up before mailbox ack was ready " + "after submitting %s to RPU. only " + "waited %d msecs on req %u but awakened" + " with unmatched ack %u\n", + info->name, + jiffies_to_msecs(ret), + req, ack); + } return -EINVAL; } - if (ret != timeout) + if (ret >= timeout) + CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " + "sending %s; timed out waiting %d msecs\n", + info->name, jiffies_to_msecs(ret)); + else CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(timeout-ret), info->name); + jiffies_to_msecs(ret), info->name); /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) |