Browse Source

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>
Andy Walls 16 years ago
parent
commit
72c2d6d3ac

+ 2 - 2
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 */

+ 4 - 3
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;

+ 7 - 14
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)

+ 41 - 43
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,

+ 6 - 1
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