From 72c2d6d3ac91d1b9efb482ff4a8dd68e3d867965 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 6 Nov 2008 01:15:41 -0300 Subject: [PATCH] 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 4 +- drivers/media/video/cx18/cx18-driver.h | 7 ++- drivers/media/video/cx18/cx18-irq.c | 21 +++---- drivers/media/video/cx18/cx18-mailbox.c | 84 ++++++++++++------------- drivers/media/video/cx18/cx18-mailbox.h | 7 ++- 5 files changed, 60 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 6799eab8b6ac..3079e466e6e7 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -446,6 +446,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->i2c_bus_lock[0]); mutex_init(&cx->i2c_bus_lock[1]); mutex_init(&cx->gpio_lock); + mutex_init(&cx->epu2apu_mb_lock); + mutex_init(&cx->epu2cpu_mb_lock); spin_lock_init(&cx->lock); @@ -466,8 +468,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); - init_waitqueue_head(&cx->mb_epu_waitq); - init_waitqueue_head(&cx->mb_hpu_waitq); init_waitqueue_head(&cx->dma_waitq); /* VBI */ diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 04f1c624da7c..e2ec15549783 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -378,7 +378,10 @@ struct cx18 { u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ unsigned mdl_offset; - struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct cx18_av_state av_state; @@ -428,8 +431,6 @@ struct cx18 { wait_queue_head_t mb_apu_waitq; wait_queue_head_t mb_cpu_waitq; - wait_queue_head_t mb_epu_waitq; - wait_queue_head_t mb_hpu_waitq; wait_queue_head_t cap_w; /* when the current DMA is finished this queue is woken up */ wait_queue_head_t dma_waitq; diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index 33f56c61ca74..37b931055d3a 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -38,7 +38,7 @@ void cx18_work_handler(struct work_struct *work) cx18_dvb_work_handler(cx); } -static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { u32 handle = mb->args[0]; struct cx18_stream *s = NULL; @@ -59,7 +59,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) " handle %d\n", handle); mb->error = CXERR_NOT_OPEN; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); return; } @@ -86,13 +86,13 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) } mb->error = 0; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); wake_up(&cx->dma_waitq); if (s->id != -1) wake_up(&s->waitq); } -static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { char str[256] = { 0 }; char *p; @@ -102,7 +102,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252); str[252] = 0; } - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); p = strchr(str, '.'); if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) @@ -119,10 +119,10 @@ static void epu_cmd(struct cx18 *cx, u32 sw1) switch (mb.cmd) { case CX18_EPU_DMA_DONE: - epu_dma_done(cx, &mb); + epu_dma_done(cx, &mb, CPU); break; case CX18_EPU_DEBUG: - epu_debug(cx, &mb); + epu_debug(cx, &mb, CPU); break; default: CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", @@ -135,11 +135,6 @@ static void epu_cmd(struct cx18 *cx, u32 sw1) cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); } - - if (sw1 & IRQ_HPU_TO_EPU) { - cx18_memcpy_fromio(cx, &mb, &cx->scb->hpu2epu_mb, sizeof(mb)); - CX18_WARN("Unknown HPU_TO_EPU mailbox command %#08x\n", mb.cmd); - } } static void xpu_ack(struct cx18 *cx, u32 sw2) @@ -148,8 +143,6 @@ static void xpu_ack(struct cx18 *cx, u32 sw2) wake_up(&cx->mb_cpu_waitq); if (sw2 & IRQ_APU_TO_EPU_ACK) wake_up(&cx->mb_apu_waitq); - if (sw2 & IRQ_HPU_TO_EPU_ACK) - wake_up(&cx->mb_hpu_waitq); } irqreturn_t cx18_irq_handler(int irq, void *dev_id) 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, diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index d995641536b3..54758f32db1e 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -30,6 +30,11 @@ #define MB_RESERVED_HANDLE_0 0 #define MB_RESERVED_HANDLE_1 0xFFFFFFFF +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + struct cx18; /* The cx18_mailbox struct is the mailbox structure which is used for passing @@ -68,6 +73,6 @@ int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); int cx18_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); -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); #endif -- 2.30.2