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>
This commit is contained in:
Andy Walls 2008-11-06 01:15:41 -03:00 committed by Mauro Carvalho Chehab
parent f68d0cf567
commit 72c2d6d3ac
5 changed files with 60 additions and 63 deletions

View 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 */

View 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;

View 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)

View file

@ -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,

View file

@ -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