From 0e0809a58869e3e422985f868ad5e0da1fc0ba85 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Sep 2010 09:01:26 -0300 Subject: [PATCH] V4L/DVB: videobuf: add queue argument to videobuf_waiton() videobuf_waiton() must unlock and relock ext_lock if it has to wait. For that to happen it needs the videobuf_queue pointer. Don't attempt to unlock/relock q->ext_lock unless it was locked in the first place. vb->state has to be protected by a spinlock to be safe. This patch is based on code from Mauro Carvalho Chehab . [mchehab@redhat.com: add extra argument to a few missing places] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_fops.c | 2 +- drivers/media/video/bt8xx/bttv-risc.c | 2 +- drivers/media/video/cx23885/cx23885-core.c | 2 +- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/fsl-viu.c | 2 +- drivers/media/video/mem2mem_testdev.c | 2 +- drivers/media/video/mx1_camera.c | 2 +- drivers/media/video/mx2_camera.c | 2 +- drivers/media/video/mx3_camera.c | 2 +- drivers/media/video/omap24xxcam.c | 2 +- drivers/media/video/pxa_camera.c | 2 +- drivers/media/video/saa7134/saa7134-core.c | 2 +- drivers/media/video/sh_mobile_ceu_camera.c | 2 +- drivers/media/video/sh_vou.c | 2 +- drivers/media/video/tlg2300/pd-video.c | 4 +- drivers/media/video/videobuf-core.c | 51 +++++++++++++++------- drivers/media/video/videobuf-dvb.c | 2 +- drivers/staging/cx25821/cx25821-core.c | 2 +- drivers/staging/dt3155v4l/dt3155v4l.c | 8 ++-- include/media/videobuf-core.h | 3 +- 20 files changed, 60 insertions(+), 38 deletions(-) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 4da2a54cb8bd..e3fedc60fe77 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -56,7 +56,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); buf->vb.state = VIDEOBUF_NEEDS_INIT; diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 0fa9f39f37a3..9b57d091da48 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f6b62e7398af..2a34e955dad2 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1221,7 +1221,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index e46dd7ed63ce..2e145f0a5fd9 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -217,7 +217,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 0b318bed4d52..211e83963a46 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c @@ -426,7 +426,7 @@ static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(vq, &buf->vb, 0, 0); if (vq->int_ops && vq->int_ops->vaddr) vaddr = vq->int_ops->vaddr(vb); diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index a7210d981388..3b19f5b25a72 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -848,7 +848,7 @@ static void queue_init(void *priv, struct videobuf_queue *vq, videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev, &ctx->dev->irqlock, type, V4L2_FIELD_NONE, - sizeof(struct m2mtest_buffer), priv); + sizeof(struct m2mtest_buffer), priv, NULL); } diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 5c17f9ec3d7c..e8a5ffcb6f06 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -161,7 +161,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(vq, vb, 0, 0); videobuf_dma_contig_free(vq, vb); vb->state = VIDEOBUF_NEEDS_INIT; diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index b6ea67221d1d..38d09474da13 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -463,7 +463,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(vq, vb, 0, 0); videobuf_dma_contig_free(vq, vb); dev_dbg(&icd->dev, "%s freed\n", __func__); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index a9be14c23912..a13076969e5a 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -185,7 +185,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(vq, vb, 0, 0); if (txd) { ichan = to_idmac_chan(txd->chan); async_tx_ack(txd); diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 926a5aa6f7f8..13c09f5fa875 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -420,7 +420,7 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq, struct videobuf_dmabuf *dma = videobuf_to_dma(vb); /* wait for buffer, especially to get out of the sgdma queue */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(vbq, vb, 0, 0); if (vb->memory == V4L2_MEMORY_MMAP) { dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction); diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 9de7d59916bd..109ba99ae121 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -275,7 +275,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(vq, &buf->vb, 0, 0); videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 40bc635e8a3f..c424c4574d49 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -255,7 +255,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); buf->vb.state = VIDEOBUF_NEEDS_INIT; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 2b24bd0de3ad..39211628d427 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -245,7 +245,7 @@ static void free_buffer(struct videobuf_queue *vq, if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(vq, &buf->vb, 0, 0); videobuf_dma_contig_free(vq, &buf->vb); dev_dbg(dev, "%s freed\n", __func__); buf->vb.state = VIDEOBUF_NEEDS_INIT; diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c index d394187eb701..d3acd02a1632 100644 --- a/drivers/media/video/sh_vou.c +++ b/drivers/media/video/sh_vou.c @@ -230,7 +230,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) BUG_ON(in_interrupt()); /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(vq, vb, 0, 0); videobuf_dma_contig_free(vq, vb); vb->state = VIDEOBUF_NEEDS_INIT; } diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c index d0cc012f7ae6..a1ffe18640fe 100644 --- a/drivers/media/video/tlg2300/pd-video.c +++ b/drivers/media/video/tlg2300/pd-video.c @@ -1434,7 +1434,7 @@ static int pd_video_open(struct file *file) V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,/* video is interlacd */ sizeof(struct videobuf_buffer),/*it's enough*/ - front); + front, NULL); } else if (vfd->vfl_type == VFL_TYPE_VBI && !(pd->state & POSEIDON_STATE_VBI)) { front = kzalloc(sizeof(struct front_face), GFP_KERNEL); @@ -1451,7 +1451,7 @@ static int pd_video_open(struct file *file) V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_NONE, /* vbi is NONE mode */ sizeof(struct videobuf_buffer), - front); + front, NULL); } else { /* maybe add FM support here */ log("other "); diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index a32ef8eafc01..8979f91fa8e5 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -73,25 +73,46 @@ struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q) } EXPORT_SYMBOL_GPL(videobuf_alloc_vb); -#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\ - vb->state != VIDEOBUF_QUEUED) -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) +static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb) { + unsigned long flags; + bool rc; + + spin_lock_irqsave(q->irqlock, flags); + rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED; + spin_unlock_irqrestore(q->irqlock, flags); + return rc; +}; + +int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, + int non_blocking, int intr) +{ + bool is_ext_locked; + int ret = 0; + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); if (non_blocking) { - if (WAITON_CONDITION) + if (is_state_active_or_queued(q, vb)) return 0; - else - return -EAGAIN; + return -EAGAIN; } - if (intr) - return wait_event_interruptible(vb->done, WAITON_CONDITION); - else - wait_event(vb->done, WAITON_CONDITION); + is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); - return 0; + /* Release vdev lock to prevent this wait from blocking outside access to + the device. */ + if (is_ext_locked) + mutex_unlock(q->ext_lock); + if (intr) + ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb)); + else + wait_event(vb->done, is_state_active_or_queued(q, vb)); + /* Relock */ + if (is_ext_locked) + mutex_lock(q->ext_lock); + + return ret; } EXPORT_SYMBOL_GPL(videobuf_waiton); @@ -671,7 +692,7 @@ static int stream_next_buffer(struct videobuf_queue *q, goto done; buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, nonblocking, 1); + retval = videobuf_waiton(q, buf, nonblocking, 1); if (retval < 0) goto done; @@ -799,7 +820,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, q->read_buf); spin_unlock_irqrestore(q->irqlock, flags); - retval = videobuf_waiton(q->read_buf, 0, 0); + retval = videobuf_waiton(q, q->read_buf, 0, 0); if (0 == retval) { CALL(q, sync, q, q->read_buf); if (VIDEOBUF_ERROR == q->read_buf->state) @@ -911,7 +932,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); + retval = videobuf_waiton(q, q->read_buf, nonblocking, 1); if (0 != retval) goto done; @@ -1061,7 +1082,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, list_del(&q->read_buf->stream); q->read_off = 0; } - rc = videobuf_waiton(q->read_buf, nonblocking, 1); + rc = videobuf_waiton(q, q->read_buf, nonblocking, 1); if (rc < 0) { if (0 == retval) retval = rc; diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 3f76398968b8..3de7c7e4402d 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -57,7 +57,7 @@ static int videobuf_dvb_thread(void *data) buf = list_entry(dvb->dvbq.stream.next, struct videobuf_buffer, stream); list_del(&buf->stream); - err = videobuf_waiton(buf,0,1); + err = videobuf_waiton(&dvb->dvbq, buf, 0, 1); /* no more feeds left or stop_feed() asked us to quit */ if (0 == dvb->nfeeds) diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c index c487c19256b9..03391f413397 100644 --- a/drivers/staging/cx25821/cx25821-core.c +++ b/drivers/staging/cx25821/cx25821-core.c @@ -1319,7 +1319,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c index fd48b38e797c..b996697e7eb2 100644 --- a/drivers/staging/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/dt3155v4l/dt3155v4l.c @@ -293,7 +293,7 @@ static void dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { if (vb->state == VIDEOBUF_ACTIVE) - videobuf_waiton(vb, 0, 0); /* FIXME: cannot be interrupted */ + videobuf_waiton(q, vb, 0, 0); /* FIXME: cannot be interrupted */ videobuf_dma_contig_free(q, vb); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -440,7 +440,7 @@ dt3155_open(struct file *filp) videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops, &pd->pdev->dev, &pd->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), pd); + sizeof(struct videobuf_buffer), pd, NULL); /* disable all irqs, clear all irq flags */ iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); @@ -494,7 +494,7 @@ dt3155_release(struct file *filp) tmp = pd->curr_buf; spin_unlock_irqrestore(&pd->lock, flags); if (tmp) - videobuf_waiton(tmp, 0, 1); /* block, interruptible */ + videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */ dt3155_stop_acq(pd); videobuf_stop(pd->vidq); pd->acq_fp = NULL; @@ -603,7 +603,7 @@ dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type) tmp = pd->curr_buf; spin_unlock_irqrestore(&pd->lock, flags); if (tmp) - videobuf_waiton(tmp, 0, 1); /* block, interruptible */ + videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */ return ret; } diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9a4194557e4a..1d3835fc26be 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -180,7 +180,8 @@ static inline void videobuf_queue_unlock(struct videobuf_queue *q) mutex_unlock(&q->vb_lock); } -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); +int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, + int non_blocking, int intr); int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf);