V4L/DVB (9593): cx18: Add outgoing mailbox mutexes and check for ack via waitq vs...
authorAndy Walls <awalls@radix.net>
Thu, 6 Nov 2008 04:15:41 +0000 (01:15 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:38:02 +0000 (09:38 -0200)
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>
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-mailbox.h

index 6799eab..3079e46 100644 (file)
@@ -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 */
index 04f1c62..e2ec155 100644 (file)
@@ -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;
index 33f56c6..37b9310 100644 (file)
@@ -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)
index acff7df..d2975a2 100644 (file)
 #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,
index d995641..54758f3 100644 (file)
 #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