diff options
author | Andy Walls <awalls@radix.net> | 2008-11-06 01:15:41 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 09:38:02 -0200 |
commit | 72c2d6d3ac91d1b9efb482ff4a8dd68e3d867965 (patch) | |
tree | 0e80f865ac4763e30eb7777360fbf3d860b140f0 /drivers/media/video/cx18/cx18-mailbox.c | |
parent | f68d0cf56761128e85ebc98d8de4776b89c30279 (diff) | |
download | lwn-72c2d6d3ac91d1b9efb482ff4a8dd68e3d867965.tar.gz lwn-72c2d6d3ac91d1b9efb482ff4a8dd68e3d867965.zip |
V4L/DVB (9593): cx18: Add outgoing mailbox mutexes and check for ack via waitq vs poll
Add mutexes to ensure exclusive access for outgoing driver to CX23418 mailboxes.
Also wait on a waitq for mailbox acknowledgement from the CX23418 instead of
polling.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-mailbox.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 84 |
1 files changed, 41 insertions, 43 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index acff7dfb60df..d2975a2e6cb7 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -30,11 +30,6 @@ #define API_FAST (1 << 2) /* Short timeout */ #define API_SLOW (1 << 3) /* Additional 300ms timeout */ -#define APU 0 -#define CPU 1 -#define EPU 2 -#define HPU 3 - struct cx18_api_info { u32 cmd; u8 flags; /* Flags, see above */ @@ -117,10 +112,7 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq); break; - case HPU: - mb = &cx->scb->epu2hpu_mb; - *state = cx18_readl(cx, &cx->scb->hpu_state); - *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq); + default: break; } @@ -142,25 +134,12 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu return NULL; } -long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu) { - const struct cx18_api_info *info = find_api_info(mb->cmd); struct cx18_mailbox __iomem *ack_mb; u32 ack_irq; - u8 rpu = CPU; - - if (info == NULL && mb->cmd) { - CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); - return -EINVAL; - } - if (info) - rpu = info->rpu; switch (rpu) { - case HPU: - ack_irq = IRQ_EPU_TO_HPU_ACK; - ack_mb = &cx->scb->hpu2epu_mb; - break; case APU: ack_irq = IRQ_EPU_TO_APU_ACK; ack_mb = &cx->scb->apu2epu_mb; @@ -170,7 +149,8 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) ack_mb = &cx->scb->cpu2epu_mb; break; default: - CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + CX18_WARN("Unhandled RPU (%d) for command %x ack\n", + rpu, mb->cmd); return -EINVAL; } @@ -187,8 +167,8 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) u32 state = 0, irq = 0, req, oldreq, err; struct cx18_mailbox __iomem *mb; wait_queue_head_t *waitq; + struct mutex *mb_lock; int timeout = 100; - int cnt = 0; int sig = 0; int i; @@ -201,10 +181,27 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_API("%s\n", info->name); else CX18_DEBUG_API("%s\n", info->name); + + switch (info->rpu) { + case APU: + waitq = &cx->mb_apu_waitq; + mb_lock = &cx->epu2apu_mb_lock; + break; + case CPU: + waitq = &cx->mb_cpu_waitq; + mb_lock = &cx->epu2cpu_mb_lock; + break; + default: + CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); + return -EINVAL; + } + + mutex_lock(mb_lock); cx18_setup_page(cx, SCB_OFFSET); mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); if (mb == NULL) { + mutex_unlock(mb_lock); CX18_ERR("mb %s busy\n", info->name); return -EBUSY; } @@ -216,34 +213,35 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) cx18_writel(cx, 0, &mb->error); cx18_writel(cx, req, &mb->request); - switch (info->rpu) { - case APU: waitq = &cx->mb_apu_waitq; break; - case CPU: waitq = &cx->mb_cpu_waitq; break; - case EPU: waitq = &cx->mb_epu_waitq; break; - case HPU: waitq = &cx->mb_hpu_waitq; break; - default: return -EINVAL; - } if (info->flags & API_FAST) timeout /= 2; cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) - && cnt < 660) { - if (cnt > 200 && !in_atomic()) - sig = cx18_msleep_timeout(10, 1); - cnt++; - } - if (sig) - return -EINTR; - if (cnt == 660) { + sig = wait_event_interruptible_timeout( + *waitq, + cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), + msecs_to_jiffies(timeout)); + if (sig == 0) { + /* Timed out */ cx18_writel(cx, oldreq, &mb->request); - CX18_ERR("mb %s failed\n", info->name); + mutex_unlock(mb_lock); + CX18_ERR("sending %s timed out waiting for RPU to respond\n", + info->name); return -EINVAL; + } else if (sig < 0) { + /* Interrupted */ + cx18_writel(cx, oldreq, &mb->request); + mutex_unlock(mb_lock); + CX18_WARN("sending %s interrupted waiting for RPU to respond\n", + info->name); + return -EINTR; } + for (i = 0; i < MAX_MB_ARGUMENTS; i++) data[i] = cx18_readl(cx, &mb->args[i]); err = cx18_readl(cx, &mb->error); - if (!in_atomic() && (info->flags & API_SLOW)) + mutex_unlock(mb_lock); + if (info->flags & API_SLOW) cx18_msleep_timeout(300, 0); if (err) CX18_DEBUG_API("mailbox error %08x for command %s\n", err, |