The patch number 9593 was added via Andy Walls <[EMAIL PROTECTED]>
to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel
If anyone has any objections, please let us know by sending a message to:
[EMAIL PROTECTED]
------
From: Andy Walls <[EMAIL PROTECTED]>
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.
Priority: high
Signed-off-by: Andy Walls <[EMAIL PROTECTED]>
---
linux/drivers/media/video/cx18/cx18-driver.c | 4
linux/drivers/media/video/cx18/cx18-driver.h | 7 -
linux/drivers/media/video/cx18/cx18-irq.c | 21 +---
linux/drivers/media/video/cx18/cx18-mailbox.c | 90 ++++++++----------
linux/drivers/media/video/cx18/cx18-mailbox.h | 7 +
5 files changed, 63 insertions(+), 66 deletions(-)
diff -r 5ff66fc94628 -r 0de4da9f514f
linux/drivers/media/video/cx18/cx18-driver.c
--- a/linux/drivers/media/video/cx18/cx18-driver.c Wed Nov 05 19:19:15
2008 -0500
+++ b/linux/drivers/media/video/cx18/cx18-driver.c Wed Nov 05 23:15:41
2008 -0500
@@ -446,6 +446,8 @@ static int __devinit cx18_init_struct1(s
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);
@@ -470,8 +472,6 @@ static int __devinit cx18_init_struct1(s
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 -r 5ff66fc94628 -r 0de4da9f514f
linux/drivers/media/video/cx18/cx18-driver.h
--- a/linux/drivers/media/video/cx18/cx18-driver.h Wed Nov 05 19:19:15
2008 -0500
+++ b/linux/drivers/media/video/cx18/cx18-driver.h Wed Nov 05 23:15:41
2008 -0500
@@ -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 -r 5ff66fc94628 -r 0de4da9f514f linux/drivers/media/video/cx18/cx18-irq.c
--- a/linux/drivers/media/video/cx18/cx18-irq.c Wed Nov 05 19:19:15 2008 -0500
+++ b/linux/drivers/media/video/cx18/cx18-irq.c Wed Nov 05 23:15:41 2008 -0500
@@ -44,7 +44,7 @@ void cx18_work_handler(void *arg)
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;
@@ -65,7 +65,7 @@ static void epu_dma_done(struct cx18 *cx
" handle %d\n", handle);
mb->error = CXERR_NOT_OPEN;
mb->cmd = 0;
- cx18_mb_ack(cx, mb);
+ cx18_mb_ack(cx, mb, rpu);
return;
}
@@ -92,13 +92,13 @@ static void epu_dma_done(struct cx18 *cx
}
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;
@@ -108,7 +108,7 @@ static void epu_debug(struct cx18 *cx, s
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)
@@ -125,10 +125,10 @@ static void epu_cmd(struct cx18 *cx, u32
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",
@@ -141,11 +141,6 @@ static void epu_cmd(struct cx18 *cx, u32
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)
@@ -154,8 +149,6 @@ static void xpu_ack(struct cx18 *cx, u32
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);
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
diff -r 5ff66fc94628 -r 0de4da9f514f
linux/drivers/media/video/cx18/cx18-mailbox.c
--- a/linux/drivers/media/video/cx18/cx18-mailbox.c Wed Nov 05 19:19:15
2008 -0500
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c Wed Nov 05 23:15:41
2008 -0500
@@ -29,11 +29,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;
@@ -117,10 +112,7 @@ static struct cx18_mailbox __iomem *cx18
*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
return NULL;
}
-long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
-{
- const struct cx18_api_info *info = find_api_info(mb->cmd);
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu)
+{
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
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 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
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
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)
+ 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);
+ 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;
- if (cnt == 660) {
- cx18_writel(cx, oldreq, &mb->request);
- CX18_ERR("mb %s failed\n", info->name);
- return -EINVAL;
- }
+ }
+
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 -r 5ff66fc94628 -r 0de4da9f514f
linux/drivers/media/video/cx18/cx18-mailbox.h
--- a/linux/drivers/media/video/cx18/cx18-mailbox.h Wed Nov 05 19:19:15
2008 -0500
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.h Wed Nov 05 23:15:41
2008 -0500
@@ -29,6 +29,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;
@@ -68,6 +73,6 @@ int cx18_vapi(struct cx18 *cx, 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
---
Patch is available at:
http://linuxtv.org/hg/v4l-dvb/rev/0de4da9f514f7333bde0c6aac9baab85e3ef90fe
_______________________________________________
linuxtv-commits mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits