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:
parent
f68d0cf567
commit
72c2d6d3ac
5 changed files with 60 additions and 63 deletions
|
@ -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[0]);
|
||||||
mutex_init(&cx->i2c_bus_lock[1]);
|
mutex_init(&cx->i2c_bus_lock[1]);
|
||||||
mutex_init(&cx->gpio_lock);
|
mutex_init(&cx->gpio_lock);
|
||||||
|
mutex_init(&cx->epu2apu_mb_lock);
|
||||||
|
mutex_init(&cx->epu2cpu_mb_lock);
|
||||||
|
|
||||||
spin_lock_init(&cx->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->cap_w);
|
||||||
init_waitqueue_head(&cx->mb_apu_waitq);
|
init_waitqueue_head(&cx->mb_apu_waitq);
|
||||||
init_waitqueue_head(&cx->mb_cpu_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);
|
init_waitqueue_head(&cx->dma_waitq);
|
||||||
|
|
||||||
/* VBI */
|
/* VBI */
|
||||||
|
|
|
@ -379,6 +379,9 @@ struct cx18 {
|
||||||
u32 hw_flags; /* Hardware description of the board */
|
u32 hw_flags; /* Hardware description of the board */
|
||||||
unsigned mdl_offset;
|
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;
|
struct cx18_av_state av_state;
|
||||||
|
|
||||||
|
@ -428,8 +431,6 @@ struct cx18 {
|
||||||
|
|
||||||
wait_queue_head_t mb_apu_waitq;
|
wait_queue_head_t mb_apu_waitq;
|
||||||
wait_queue_head_t mb_cpu_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;
|
wait_queue_head_t cap_w;
|
||||||
/* when the current DMA is finished this queue is woken up */
|
/* when the current DMA is finished this queue is woken up */
|
||||||
wait_queue_head_t dma_waitq;
|
wait_queue_head_t dma_waitq;
|
||||||
|
|
|
@ -38,7 +38,7 @@ void cx18_work_handler(struct work_struct *work)
|
||||||
cx18_dvb_work_handler(cx);
|
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];
|
u32 handle = mb->args[0];
|
||||||
struct cx18_stream *s = NULL;
|
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);
|
" handle %d\n", handle);
|
||||||
mb->error = CXERR_NOT_OPEN;
|
mb->error = CXERR_NOT_OPEN;
|
||||||
mb->cmd = 0;
|
mb->cmd = 0;
|
||||||
cx18_mb_ack(cx, mb);
|
cx18_mb_ack(cx, mb, rpu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +86,13 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
|
||||||
}
|
}
|
||||||
mb->error = 0;
|
mb->error = 0;
|
||||||
mb->cmd = 0;
|
mb->cmd = 0;
|
||||||
cx18_mb_ack(cx, mb);
|
cx18_mb_ack(cx, mb, rpu);
|
||||||
wake_up(&cx->dma_waitq);
|
wake_up(&cx->dma_waitq);
|
||||||
if (s->id != -1)
|
if (s->id != -1)
|
||||||
wake_up(&s->waitq);
|
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 str[256] = { 0 };
|
||||||
char *p;
|
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);
|
cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
|
||||||
str[252] = 0;
|
str[252] = 0;
|
||||||
}
|
}
|
||||||
cx18_mb_ack(cx, mb);
|
cx18_mb_ack(cx, mb, rpu);
|
||||||
CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
|
CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
|
||||||
p = strchr(str, '.');
|
p = strchr(str, '.');
|
||||||
if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > 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) {
|
switch (mb.cmd) {
|
||||||
case CX18_EPU_DMA_DONE:
|
case CX18_EPU_DMA_DONE:
|
||||||
epu_dma_done(cx, &mb);
|
epu_dma_done(cx, &mb, CPU);
|
||||||
break;
|
break;
|
||||||
case CX18_EPU_DEBUG:
|
case CX18_EPU_DEBUG:
|
||||||
epu_debug(cx, &mb);
|
epu_debug(cx, &mb, CPU);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n",
|
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_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb));
|
||||||
CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd);
|
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)
|
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);
|
wake_up(&cx->mb_cpu_waitq);
|
||||||
if (sw2 & IRQ_APU_TO_EPU_ACK)
|
if (sw2 & IRQ_APU_TO_EPU_ACK)
|
||||||
wake_up(&cx->mb_apu_waitq);
|
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)
|
irqreturn_t cx18_irq_handler(int irq, void *dev_id)
|
||||||
|
|
|
@ -30,11 +30,6 @@
|
||||||
#define API_FAST (1 << 2) /* Short timeout */
|
#define API_FAST (1 << 2) /* Short timeout */
|
||||||
#define API_SLOW (1 << 3) /* Additional 300ms 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 {
|
struct cx18_api_info {
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
u8 flags; /* Flags, see above */
|
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);
|
*irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HPU:
|
default:
|
||||||
mb = &cx->scb->epu2hpu_mb;
|
|
||||||
*state = cx18_readl(cx, &cx->scb->hpu_state);
|
|
||||||
*irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,25 +134,12 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu
|
||||||
return NULL;
|
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;
|
struct cx18_mailbox __iomem *ack_mb;
|
||||||
u32 ack_irq;
|
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) {
|
switch (rpu) {
|
||||||
case HPU:
|
|
||||||
ack_irq = IRQ_EPU_TO_HPU_ACK;
|
|
||||||
ack_mb = &cx->scb->hpu2epu_mb;
|
|
||||||
break;
|
|
||||||
case APU:
|
case APU:
|
||||||
ack_irq = IRQ_EPU_TO_APU_ACK;
|
ack_irq = IRQ_EPU_TO_APU_ACK;
|
||||||
ack_mb = &cx->scb->apu2epu_mb;
|
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;
|
ack_mb = &cx->scb->cpu2epu_mb;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
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;
|
u32 state = 0, irq = 0, req, oldreq, err;
|
||||||
struct cx18_mailbox __iomem *mb;
|
struct cx18_mailbox __iomem *mb;
|
||||||
wait_queue_head_t *waitq;
|
wait_queue_head_t *waitq;
|
||||||
|
struct mutex *mb_lock;
|
||||||
int timeout = 100;
|
int timeout = 100;
|
||||||
int cnt = 0;
|
|
||||||
int sig = 0;
|
int sig = 0;
|
||||||
int i;
|
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);
|
CX18_DEBUG_HI_API("%s\n", info->name);
|
||||||
else
|
else
|
||||||
CX18_DEBUG_API("%s\n", info->name);
|
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);
|
cx18_setup_page(cx, SCB_OFFSET);
|
||||||
mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
|
mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
|
||||||
|
|
||||||
if (mb == NULL) {
|
if (mb == NULL) {
|
||||||
|
mutex_unlock(mb_lock);
|
||||||
CX18_ERR("mb %s busy\n", info->name);
|
CX18_ERR("mb %s busy\n", info->name);
|
||||||
return -EBUSY;
|
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, 0, &mb->error);
|
||||||
cx18_writel(cx, req, &mb->request);
|
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)
|
if (info->flags & API_FAST)
|
||||||
timeout /= 2;
|
timeout /= 2;
|
||||||
cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
|
cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
|
||||||
|
|
||||||
while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request)
|
sig = wait_event_interruptible_timeout(
|
||||||
&& cnt < 660) {
|
*waitq,
|
||||||
if (cnt > 200 && !in_atomic())
|
cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
|
||||||
sig = cx18_msleep_timeout(10, 1);
|
msecs_to_jiffies(timeout));
|
||||||
cnt++;
|
if (sig == 0) {
|
||||||
}
|
/* Timed out */
|
||||||
if (sig)
|
|
||||||
return -EINTR;
|
|
||||||
if (cnt == 660) {
|
|
||||||
cx18_writel(cx, oldreq, &mb->request);
|
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;
|
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++)
|
for (i = 0; i < MAX_MB_ARGUMENTS; i++)
|
||||||
data[i] = cx18_readl(cx, &mb->args[i]);
|
data[i] = cx18_readl(cx, &mb->args[i]);
|
||||||
err = cx18_readl(cx, &mb->error);
|
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);
|
cx18_msleep_timeout(300, 0);
|
||||||
if (err)
|
if (err)
|
||||||
CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
|
CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#define MB_RESERVED_HANDLE_0 0
|
#define MB_RESERVED_HANDLE_0 0
|
||||||
#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
|
#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define APU 0
|
||||||
|
#define CPU 1
|
||||||
|
#define EPU 2
|
||||||
|
#define HPU 3
|
||||||
|
|
||||||
struct cx18;
|
struct cx18;
|
||||||
|
|
||||||
/* The cx18_mailbox struct is the mailbox structure which is used for passing
|
/* 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_vapi(struct cx18 *cx, u32 cmd, int args, ...);
|
||||||
int cx18_api_func(void *priv, u32 cmd, int in, int out,
|
int cx18_api_func(void *priv, u32 cmd, int in, int out,
|
||||||
u32 data[CX2341X_MBOX_MAX_DATA]);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue