aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2013-01-18 10:02:32 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-05 14:40:36 -0500
commit03878bb473bb46cf8514223d8c955420b1ef73bc (patch)
tree2586d8c7f05b58d6a1c2342298348a40121c9f81 /drivers/media/platform
parent81b9f70210b62e256cf63eb8f703042ef44e4cdd (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.c2
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.c35
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.h2
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;