diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-01-18 10:02:32 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-05 14:40:36 -0500 |
commit | 03878bb473bb46cf8514223d8c955420b1ef73bc (patch) | |
tree | 2586d8c7f05b58d6a1c2342298348a40121c9f81 /drivers/media/platform | |
parent | 81b9f70210b62e256cf63eb8f703042ef44e4cdd (diff) |
[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 <s.nawrocki@samsung.com>
Signed-off-by: Kyugmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r-- | drivers/media/platform/s5p-fimc/fimc-lite-reg.c | 2 | ||||
-rw-r--r-- | drivers/media/platform/s5p-fimc/fimc-lite.c | 35 | ||||
-rw-r--r-- | 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) | |||
65 | u32 cfg, intsrc; | 65 | u32 cfg, intsrc; |
66 | 66 | ||
67 | /* Select interrupts to be enabled for each output mode */ | 67 | /* Select interrupts to be enabled for each output mode */ |
68 | if (dev->out_path == FIMC_IO_DMA) { | 68 | if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { |
69 | intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | | 69 | intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | |
70 | FLITE_REG_CIGCTRL_IRQ_LASTEN | | 70 | FLITE_REG_CIGCTRL_IRQ_LASTEN | |
71 | FLITE_REG_CIGCTRL_IRQ_STARTEN; | 71 | 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) | |||
260 | wake_up(&fimc->irq_queue); | 260 | wake_up(&fimc->irq_queue); |
261 | } | 261 | } |
262 | 262 | ||
263 | if (fimc->out_path != FIMC_IO_DMA) | 263 | if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) |
264 | goto done; | 264 | goto done; |
265 | 265 | ||
266 | if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && | 266 | if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && |
@@ -465,7 +465,7 @@ static int fimc_lite_open(struct file *file) | |||
465 | mutex_lock(&me->parent->graph_mutex); | 465 | mutex_lock(&me->parent->graph_mutex); |
466 | 466 | ||
467 | mutex_lock(&fimc->lock); | 467 | mutex_lock(&fimc->lock); |
468 | if (fimc->out_path != FIMC_IO_DMA) { | 468 | if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { |
469 | ret = -EBUSY; | 469 | ret = -EBUSY; |
470 | goto done; | 470 | goto done; |
471 | } | 471 | } |
@@ -479,7 +479,8 @@ static int fimc_lite_open(struct file *file) | |||
479 | if (ret < 0) | 479 | if (ret < 0) |
480 | goto done; | 480 | goto done; |
481 | 481 | ||
482 | if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) { | 482 | if (++fimc->ref_count == 1 && |
483 | atomic_read(&fimc->out_path) == FIMC_IO_DMA) { | ||
483 | ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, | 484 | ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, |
484 | &fimc->vfd.entity, true); | 485 | &fimc->vfd.entity, true); |
485 | if (ret < 0) { | 486 | if (ret < 0) { |
@@ -504,7 +505,8 @@ static int fimc_lite_close(struct file *file) | |||
504 | 505 | ||
505 | mutex_lock(&fimc->lock); | 506 | mutex_lock(&fimc->lock); |
506 | 507 | ||
507 | if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { | 508 | if (--fimc->ref_count == 0 && |
509 | atomic_read(&fimc->out_path) == FIMC_IO_DMA) { | ||
508 | clear_bit(ST_FLITE_IN_USE, &fimc->state); | 510 | clear_bit(ST_FLITE_IN_USE, &fimc->state); |
509 | fimc_lite_stop_capture(fimc, false); | 511 | fimc_lite_stop_capture(fimc, false); |
510 | fimc_pipeline_call(fimc, close, &fimc->pipeline); | 512 | fimc_pipeline_call(fimc, close, &fimc->pipeline); |
@@ -1034,18 +1036,18 @@ static int fimc_lite_link_setup(struct media_entity *entity, | |||
1034 | 1036 | ||
1035 | case FLITE_SD_PAD_SOURCE_DMA: | 1037 | case FLITE_SD_PAD_SOURCE_DMA: |
1036 | if (!(flags & MEDIA_LNK_FL_ENABLED)) | 1038 | if (!(flags & MEDIA_LNK_FL_ENABLED)) |
1037 | fimc->out_path = FIMC_IO_NONE; | 1039 | atomic_set(&fimc->out_path, FIMC_IO_NONE); |
1038 | else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) | 1040 | else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) |
1039 | fimc->out_path = FIMC_IO_DMA; | 1041 | atomic_set(&fimc->out_path, FIMC_IO_DMA); |
1040 | else | 1042 | else |
1041 | ret = -EINVAL; | 1043 | ret = -EINVAL; |
1042 | break; | 1044 | break; |
1043 | 1045 | ||
1044 | case FLITE_SD_PAD_SOURCE_ISP: | 1046 | case FLITE_SD_PAD_SOURCE_ISP: |
1045 | if (!(flags & MEDIA_LNK_FL_ENABLED)) | 1047 | if (!(flags & MEDIA_LNK_FL_ENABLED)) |
1046 | fimc->out_path = FIMC_IO_NONE; | 1048 | atomic_set(&fimc->out_path, FIMC_IO_NONE); |
1047 | else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) | 1049 | else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) |
1048 | fimc->out_path = FIMC_IO_ISP; | 1050 | atomic_set(&fimc->out_path, FIMC_IO_ISP); |
1049 | else | 1051 | else |
1050 | ret = -EINVAL; | 1052 | ret = -EINVAL; |
1051 | break; | 1053 | break; |
@@ -1054,6 +1056,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, | |||
1054 | v4l2_err(sd, "Invalid pad index\n"); | 1056 | v4l2_err(sd, "Invalid pad index\n"); |
1055 | ret = -EINVAL; | 1057 | ret = -EINVAL; |
1056 | } | 1058 | } |
1059 | mb(); | ||
1057 | 1060 | ||
1058 | mutex_unlock(&fimc->lock); | 1061 | mutex_unlock(&fimc->lock); |
1059 | return ret; | 1062 | return ret; |
@@ -1123,8 +1126,10 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, | |||
1123 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 1126 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
1124 | mutex_lock(&fimc->lock); | 1127 | mutex_lock(&fimc->lock); |
1125 | 1128 | ||
1126 | if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) || | 1129 | if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP && |
1127 | (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) { | 1130 | sd->entity.stream_count > 0) || |
1131 | (atomic_read(&fimc->out_path) == FIMC_IO_DMA && | ||
1132 | vb2_is_busy(&fimc->vb_queue))) { | ||
1128 | mutex_unlock(&fimc->lock); | 1133 | mutex_unlock(&fimc->lock); |
1129 | return -EBUSY; | 1134 | return -EBUSY; |
1130 | } | 1135 | } |
@@ -1247,12 +1252,10 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) | |||
1247 | */ | 1252 | */ |
1248 | fimc->sensor = __find_remote_sensor(&sd->entity); | 1253 | fimc->sensor = __find_remote_sensor(&sd->entity); |
1249 | 1254 | ||
1250 | mutex_lock(&fimc->lock); | 1255 | if (atomic_read(&fimc->out_path) != FIMC_IO_ISP) |
1251 | if (fimc->out_path != FIMC_IO_ISP) { | ||
1252 | mutex_unlock(&fimc->lock); | ||
1253 | return -ENOIOCTLCMD; | 1256 | return -ENOIOCTLCMD; |
1254 | } | ||
1255 | 1257 | ||
1258 | mutex_lock(&fimc->lock); | ||
1256 | if (on) { | 1259 | if (on) { |
1257 | flite_hw_reset(fimc); | 1260 | flite_hw_reset(fimc); |
1258 | ret = fimc_lite_hw_init(fimc, true); | 1261 | ret = fimc_lite_hw_init(fimc, true); |
@@ -1298,7 +1301,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) | |||
1298 | memset(vfd, 0, sizeof(*vfd)); | 1301 | memset(vfd, 0, sizeof(*vfd)); |
1299 | 1302 | ||
1300 | fimc->fmt = &fimc_lite_formats[0]; | 1303 | fimc->fmt = &fimc_lite_formats[0]; |
1301 | fimc->out_path = FIMC_IO_DMA; | 1304 | atomic_set(&fimc->out_path, FIMC_IO_DMA); |
1302 | 1305 | ||
1303 | snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", | 1306 | snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", |
1304 | fimc->index); | 1307 | fimc->index); |
@@ -1589,7 +1592,7 @@ static int fimc_lite_resume(struct device *dev) | |||
1589 | INIT_LIST_HEAD(&fimc->active_buf_q); | 1592 | INIT_LIST_HEAD(&fimc->active_buf_q); |
1590 | fimc_pipeline_call(fimc, open, &fimc->pipeline, | 1593 | fimc_pipeline_call(fimc, open, &fimc->pipeline, |
1591 | &fimc->vfd.entity, false); | 1594 | &fimc->vfd.entity, false); |
1592 | fimc_lite_hw_init(fimc, fimc->out_path == FIMC_IO_ISP); | 1595 | fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP); |
1593 | clear_bit(ST_FLITE_SUSPENDED, &fimc->state); | 1596 | clear_bit(ST_FLITE_SUSPENDED, &fimc->state); |
1594 | 1597 | ||
1595 | for (i = 0; i < fimc->reqbufs_count; i++) { | 1598 | 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 { | |||
159 | unsigned long payload[FLITE_MAX_PLANES]; | 159 | unsigned long payload[FLITE_MAX_PLANES]; |
160 | struct flite_frame inp_frame; | 160 | struct flite_frame inp_frame; |
161 | struct flite_frame out_frame; | 161 | struct flite_frame out_frame; |
162 | enum fimc_datapath out_path; | 162 | atomic_t out_path; |
163 | unsigned int source_subdev_grp_id; | 163 | unsigned int source_subdev_grp_id; |
164 | 164 | ||
165 | unsigned long state; | 165 | unsigned long state; |