From 03878bb473bb46cf8514223d8c955420b1ef73bc Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 18 Jan 2013 12:02:32 -0300 Subject: [PATCH] [media] s5p-fimc: fimc-lite: Prevent deadlock at STREAMON/OFF ioctls This patch fixes regression introduced in commit 6319d6a002beb26631 '[media] fimc-lite: Add ISP FIFO output support'. In case of a configuration where video is captured at the video node exposed by the FIMC-LITE driver there is a following video pipeline: sensor -> MIPI-CSIS.n -> FIMC-LITE.n subdev -> FIMC-LITE.n video node In this situation s_stream() handler of the FIMC-LITE.n is called back from within VIDIOC_STREAMON/OFF ioctl of the FIMC-LITE.n video node, through vb2_stream_on/off(), start/stop_streaming and fimc_pipeline_call(set_stream). The fimc->lock mutex is already held then, before invoking vidioc_streamon/off. So it must not be taken again in the s_stream() callback in this case, to avoid a deadlock. This patch makes fimc->out_path atomic_t so the mutex don't need to be taken in the FIMC-LITE subdev s_stream() callback in the DMA output case. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyugmin Park Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/s5p-fimc/fimc-lite-reg.c | 2 +- drivers/media/platform/s5p-fimc/fimc-lite.c | 35 ++++++++++--------- drivers/media/platform/s5p-fimc/fimc-lite.h | 2 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c index ad63ebf082c5..962652da3b43 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c @@ -65,7 +65,7 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev) u32 cfg, intsrc; /* Select interrupts to be enabled for each output mode */ - if (dev->out_path == FIMC_IO_DMA) { + if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | FLITE_REG_CIGCTRL_IRQ_LASTEN | FLITE_REG_CIGCTRL_IRQ_STARTEN; diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index fe6cd0c3bdd3..ef3989fe63e5 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -260,7 +260,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv) wake_up(&fimc->irq_queue); } - if (fimc->out_path != FIMC_IO_DMA) + if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) goto done; if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && @@ -465,7 +465,7 @@ static int fimc_lite_open(struct file *file) mutex_lock(&me->parent->graph_mutex); mutex_lock(&fimc->lock); - if (fimc->out_path != FIMC_IO_DMA) { + if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { ret = -EBUSY; goto done; } @@ -479,7 +479,8 @@ static int fimc_lite_open(struct file *file) if (ret < 0) goto done; - if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) { + if (++fimc->ref_count == 1 && + atomic_read(&fimc->out_path) == FIMC_IO_DMA) { ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vfd.entity, true); if (ret < 0) { @@ -504,7 +505,8 @@ static int fimc_lite_close(struct file *file) mutex_lock(&fimc->lock); - if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { + if (--fimc->ref_count == 0 && + atomic_read(&fimc->out_path) == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); @@ -1034,18 +1036,18 @@ static int fimc_lite_link_setup(struct media_entity *entity, case FLITE_SD_PAD_SOURCE_DMA: if (!(flags & MEDIA_LNK_FL_ENABLED)) - fimc->out_path = FIMC_IO_NONE; + atomic_set(&fimc->out_path, FIMC_IO_NONE); else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) - fimc->out_path = FIMC_IO_DMA; + atomic_set(&fimc->out_path, FIMC_IO_DMA); else ret = -EINVAL; break; case FLITE_SD_PAD_SOURCE_ISP: if (!(flags & MEDIA_LNK_FL_ENABLED)) - fimc->out_path = FIMC_IO_NONE; + atomic_set(&fimc->out_path, FIMC_IO_NONE); else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) - fimc->out_path = FIMC_IO_ISP; + atomic_set(&fimc->out_path, FIMC_IO_ISP); else ret = -EINVAL; break; @@ -1054,6 +1056,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, v4l2_err(sd, "Invalid pad index\n"); ret = -EINVAL; } + mb(); mutex_unlock(&fimc->lock); return ret; @@ -1123,8 +1126,10 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; mutex_lock(&fimc->lock); - if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) || - (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) { + if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP && + sd->entity.stream_count > 0) || + (atomic_read(&fimc->out_path) == FIMC_IO_DMA && + vb2_is_busy(&fimc->vb_queue))) { mutex_unlock(&fimc->lock); return -EBUSY; } @@ -1247,12 +1252,10 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) */ fimc->sensor = __find_remote_sensor(&sd->entity); - mutex_lock(&fimc->lock); - if (fimc->out_path != FIMC_IO_ISP) { - mutex_unlock(&fimc->lock); + if (atomic_read(&fimc->out_path) != FIMC_IO_ISP) return -ENOIOCTLCMD; - } + mutex_lock(&fimc->lock); if (on) { flite_hw_reset(fimc); ret = fimc_lite_hw_init(fimc, true); @@ -1298,7 +1301,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) memset(vfd, 0, sizeof(*vfd)); fimc->fmt = &fimc_lite_formats[0]; - fimc->out_path = FIMC_IO_DMA; + atomic_set(&fimc->out_path, FIMC_IO_DMA); snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", fimc->index); @@ -1589,7 +1592,7 @@ static int fimc_lite_resume(struct device *dev) INIT_LIST_HEAD(&fimc->active_buf_q); fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vfd.entity, false); - fimc_lite_hw_init(fimc, fimc->out_path == FIMC_IO_ISP); + fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); for (i = 0; i < fimc->reqbufs_count; i++) { diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h index 4576922952f3..7085761f8c4b 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.h +++ b/drivers/media/platform/s5p-fimc/fimc-lite.h @@ -159,7 +159,7 @@ struct fimc_lite { unsigned long payload[FLITE_MAX_PLANES]; struct flite_frame inp_frame; struct flite_frame out_frame; - enum fimc_datapath out_path; + atomic_t out_path; unsigned int source_subdev_grp_id; unsigned long state; -- 2.34.1