Commit dec27421 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

V4L/DVB (12520): sh-mobile-ceu-camera: do not wait for interrupt when releasing buffers

Patch

[PATCH] video: use videobuf_waiton() in sh_mobile_ceu free_buffer()

was not quite correct. It closed a race, but introduced a potential
lock-up, if for some reason an interrupt does not come. This has been
observed in tests with tw9910. This patch safely dequeues buffers without
waiting for their completion. It also moves a buffer state assignment
under a spinlock to make it atomic with queuing of the buffer.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 015715a1
...@@ -308,6 +308,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, ...@@ -308,6 +308,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb) struct videobuf_buffer *vb)
{ {
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
unsigned long flags;
spin_lock_irqsave(&pcdev->lock, flags);
if (pcdev->active == vb) {
/* disable capture (release DMA buffer), reset */
ceu_write(pcdev, CAPSR, 1 << 16);
pcdev->active = NULL;
}
if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
!list_empty(&vb->queue)) {
vb->state = VIDEOBUF_ERROR;
list_del_init(&vb->queue);
}
spin_unlock_irqrestore(&pcdev->lock, flags);
free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
} }
...@@ -327,6 +348,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) ...@@ -327,6 +348,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
spin_lock_irqsave(&pcdev->lock, flags); spin_lock_irqsave(&pcdev->lock, flags);
vb = pcdev->active; vb = pcdev->active;
if (!vb)
/* Stale interrupt from a released buffer */
goto out;
list_del_init(&vb->queue); list_del_init(&vb->queue);
if (!list_empty(&pcdev->capture)) if (!list_empty(&pcdev->capture))
...@@ -341,6 +366,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) ...@@ -341,6 +366,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
do_gettimeofday(&vb->ts); do_gettimeofday(&vb->ts);
vb->field_count++; vb->field_count++;
wake_up(&vb->done); wake_up(&vb->done);
out:
spin_unlock_irqrestore(&pcdev->lock, flags); spin_unlock_irqrestore(&pcdev->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment