Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cca0e549 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab
Browse files

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 fa48984e
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -307,6 +307,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
					   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));
}

@@ -326,6 +347,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
	spin_lock_irqsave(&pcdev->lock, flags);

	vb = pcdev->active;
	if (!vb)
		/* Stale interrupt from a released buffer */
		goto out;

	list_del_init(&vb->queue);

	if (!list_empty(&pcdev->capture))
@@ -340,6 +365,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
	do_gettimeofday(&vb->ts);
	vb->field_count++;
	wake_up(&vb->done);

out:
	spin_unlock_irqrestore(&pcdev->lock, flags);

	return IRQ_HANDLED;