Commit 03878bb4 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[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: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyugmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 81b9f702
...@@ -65,7 +65,7 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev) ...@@ -65,7 +65,7 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
u32 cfg, intsrc; u32 cfg, intsrc;
/* Select interrupts to be enabled for each output mode */ /* 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 | intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
FLITE_REG_CIGCTRL_IRQ_LASTEN | FLITE_REG_CIGCTRL_IRQ_LASTEN |
FLITE_REG_CIGCTRL_IRQ_STARTEN; FLITE_REG_CIGCTRL_IRQ_STARTEN;
......
...@@ -260,7 +260,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv) ...@@ -260,7 +260,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
wake_up(&fimc->irq_queue); wake_up(&fimc->irq_queue);
} }
if (fimc->out_path != FIMC_IO_DMA) if (atomic_read(&fimc->out_path) != FIMC_IO_DMA)
goto done; goto done;
if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
...@@ -465,7 +465,7 @@ static int fimc_lite_open(struct file *file) ...@@ -465,7 +465,7 @@ static int fimc_lite_open(struct file *file)
mutex_lock(&me->parent->graph_mutex); mutex_lock(&me->parent->graph_mutex);
mutex_lock(&fimc->lock); mutex_lock(&fimc->lock);
if (fimc->out_path != FIMC_IO_DMA) { if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
ret = -EBUSY; ret = -EBUSY;
goto done; goto done;
} }
...@@ -479,7 +479,8 @@ static int fimc_lite_open(struct file *file) ...@@ -479,7 +479,8 @@ static int fimc_lite_open(struct file *file)
if (ret < 0) if (ret < 0)
goto done; 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, ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
&fimc->vfd.entity, true); &fimc->vfd.entity, true);
if (ret < 0) { if (ret < 0) {
...@@ -504,7 +505,8 @@ static int fimc_lite_close(struct file *file) ...@@ -504,7 +505,8 @@ static int fimc_lite_close(struct file *file)
mutex_lock(&fimc->lock); 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); clear_bit(ST_FLITE_IN_USE, &fimc->state);
fimc_lite_stop_capture(fimc, false); fimc_lite_stop_capture(fimc, false);
fimc_pipeline_call(fimc, close, &fimc->pipeline); fimc_pipeline_call(fimc, close, &fimc->pipeline);
...@@ -1034,18 +1036,18 @@ static int fimc_lite_link_setup(struct media_entity *entity, ...@@ -1034,18 +1036,18 @@ static int fimc_lite_link_setup(struct media_entity *entity,
case FLITE_SD_PAD_SOURCE_DMA: case FLITE_SD_PAD_SOURCE_DMA:
if (!(flags & MEDIA_LNK_FL_ENABLED)) 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) else if (remote_ent_type == MEDIA_ENT_T_DEVNODE)
fimc->out_path = FIMC_IO_DMA; atomic_set(&fimc->out_path, FIMC_IO_DMA);
else else
ret = -EINVAL; ret = -EINVAL;
break; break;
case FLITE_SD_PAD_SOURCE_ISP: case FLITE_SD_PAD_SOURCE_ISP:
if (!(flags & MEDIA_LNK_FL_ENABLED)) 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) 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 else
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -1054,6 +1056,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, ...@@ -1054,6 +1056,7 @@ static int fimc_lite_link_setup(struct media_entity *entity,
v4l2_err(sd, "Invalid pad index\n"); v4l2_err(sd, "Invalid pad index\n");
ret = -EINVAL; ret = -EINVAL;
} }
mb();
mutex_unlock(&fimc->lock); mutex_unlock(&fimc->lock);
return ret; return ret;
...@@ -1123,8 +1126,10 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, ...@@ -1123,8 +1126,10 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_JPEG; mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&fimc->lock); mutex_lock(&fimc->lock);
if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) || if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
(fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) { sd->entity.stream_count > 0) ||
(atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
vb2_is_busy(&fimc->vb_queue))) {
mutex_unlock(&fimc->lock); mutex_unlock(&fimc->lock);
return -EBUSY; return -EBUSY;
} }
...@@ -1247,12 +1252,10 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) ...@@ -1247,12 +1252,10 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
*/ */
fimc->sensor = __find_remote_sensor(&sd->entity); fimc->sensor = __find_remote_sensor(&sd->entity);
mutex_lock(&fimc->lock); if (atomic_read(&fimc->out_path) != FIMC_IO_ISP)
if (fimc->out_path != FIMC_IO_ISP) {
mutex_unlock(&fimc->lock);
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
}
mutex_lock(&fimc->lock);
if (on) { if (on) {
flite_hw_reset(fimc); flite_hw_reset(fimc);
ret = fimc_lite_hw_init(fimc, true); ret = fimc_lite_hw_init(fimc, true);
...@@ -1298,7 +1301,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) ...@@ -1298,7 +1301,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
memset(vfd, 0, sizeof(*vfd)); memset(vfd, 0, sizeof(*vfd));
fimc->fmt = &fimc_lite_formats[0]; 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", snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
fimc->index); fimc->index);
...@@ -1589,7 +1592,7 @@ static int fimc_lite_resume(struct device *dev) ...@@ -1589,7 +1592,7 @@ static int fimc_lite_resume(struct device *dev)
INIT_LIST_HEAD(&fimc->active_buf_q); INIT_LIST_HEAD(&fimc->active_buf_q);
fimc_pipeline_call(fimc, open, &fimc->pipeline, fimc_pipeline_call(fimc, open, &fimc->pipeline,
&fimc->vfd.entity, false); &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); clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
for (i = 0; i < fimc->reqbufs_count; i++) { for (i = 0; i < fimc->reqbufs_count; i++) {
......
...@@ -159,7 +159,7 @@ struct fimc_lite { ...@@ -159,7 +159,7 @@ struct fimc_lite {
unsigned long payload[FLITE_MAX_PLANES]; unsigned long payload[FLITE_MAX_PLANES];
struct flite_frame inp_frame; struct flite_frame inp_frame;
struct flite_frame out_frame; struct flite_frame out_frame;
enum fimc_datapath out_path; atomic_t out_path;
unsigned int source_subdev_grp_id; unsigned int source_subdev_grp_id;
unsigned long state; unsigned long state;
......
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