aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2012-05-17 13:22:10 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-06-25 08:18:02 -0400
commite3fc82e8b9f550d28f05600b98bcc8c26beef2ef (patch)
tree63d5076084994e5057beed3f59c0ae15159b85fc
parent0b4b1f199d367762ddb68cb3303431fa6c84a7d6 (diff)
[media] s5p-fimc: Prevent lock-up in multiple sensor systems
The camera clocks managed by the driver were improperly reference counted and remained disabled when multiple video nodes were opened simultaneously. It manifested itself with following warning: [12.920000] WARNING: at drivers/media/video/s5p-fimc/fimc-mdevice.c:787 __fimc_md_set_camclk+0x1c0/0x1dc() [13.005000] Modules linked in: [13.005000] Backtrace: [13.040000] [<c0013084>] (dump_backtrace+0x0/0x10c) from [<c0454b70>] (dump_stack+0x18/0x1c) [13.070000] r7:00000009 r6:00000313 r5:c02d576c r4:00000000 [13.155000] [<c0454b58>] (dump_stack+0x0/0x1c) from [<c0022ec4>] (warn_slowpath_common+0x54/0x6c) [13.285000] [<c0022e70>] (warn_slowpath_common+0x0/0x6c) from [<c0022f00>] (warn_slowpath_null+0x24/0x2c) [13.360000] r9:e1981010 r8:00000000 r7:c061d3fc r6:e1981010 r5:e1981030 [13.430000] r4:00000000 [13.430000] [<c0022edc>] (warn_slowpath_null+0x0/0x2c) from [<c02d576c>] (__fimc_md_set_camclk+0x1c0/0x1dc) [13.550000] [<c02d55ac>] (__fimc_md_set_camclk+0x0/0x1dc) from [<c02d57b0>] (fimc_md_set_camclk+0x28/0x2c) [13.630000] [<c02d5788>] (fimc_md_set_camclk+0x0/0x2c) from [<c02d57e8>] (__fimc_pipeline_shutdown+0x34/0x50) [13.705000] [<c02d57b4>] (__fimc_pipeline_shutdown+0x0/0x50) from [<c02d5844>] (fimc_pipeline_shutdown+0x40/0x58) [13.765000] r5:e2391200 r4:e2357704 [13.805000] [<c02d5804>] (fimc_pipeline_shutdown+0x0/0x58) from [<c02d4754>] (fimc_capture_close+0xcc/0xe4) [13.915000] r5:e1b396c0 r4:e2357410 [13.915000] [<c02d4688>] (fimc_capture_close+0x0/0xe4) from [<c02b2d5c>] (v4l2_release+0x5c/0x80) [13.970000] r7:00000010 r6:e1d2d990 r5:e1b396c0 r4:e2394800 [14.000000] [<c02b2d00>] (v4l2_release+0x0/0x80) from [<c00b66cc>] (fput+0xc0/0x22c) [14.015000] r5:c157ef30 r4:e1b396c0 [14.015000] [<c00b660c>] (fput+0x0/0x22c) from [<c00b2ca0>] (filp_close+0x60/0x80) [14.080000] [<c00b2c40>] (filp_close+0x0/0x80) from [<c00b2d78>] (sys_close+0xb8/0xf4) [14.125000] r7:00000001 r6:e1b396c0 r5:c1400340 r4:c1400300 [14.125000] [<c00b2cc0>] (sys_close+0x0/0xf4) from [<c000f300>] (ret_fast_syscall+0x0/0x30) [14.205000] r7:00000006 r6:beee5b94 r5:00000003 r4:b6f64fac Fix this, as well as potential memory leaks due to not calling v4l2_fh_release() on some error paths. Also remove some error logs printed for events that aren't critical and are normal conditions for some system configurations. Also check if the device have been properly run-time enabled during video node open. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c46
-rw-r--r--drivers/media/video/s5p-fimc/fimc-lite.c14
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c19
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.h2
4 files changed, 38 insertions, 43 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 0fd12dfbd3db..71e483847a17 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -480,37 +480,39 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc);
480static int fimc_capture_open(struct file *file) 480static int fimc_capture_open(struct file *file)
481{ 481{
482 struct fimc_dev *fimc = video_drvdata(file); 482 struct fimc_dev *fimc = video_drvdata(file);
483 int ret = v4l2_fh_open(file); 483 int ret;
484
485 if (ret)
486 return ret;
487 484
488 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); 485 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
489 486
490 /* Return if the corresponding video mem2mem node is already opened. */
491 if (fimc_m2m_active(fimc)) 487 if (fimc_m2m_active(fimc))
492 return -EBUSY; 488 return -EBUSY;
493 489
494 set_bit(ST_CAPT_BUSY, &fimc->state); 490 set_bit(ST_CAPT_BUSY, &fimc->state);
495 pm_runtime_get_sync(&fimc->pdev->dev); 491 ret = pm_runtime_get_sync(&fimc->pdev->dev);
496 492 if (ret < 0)
497 if (++fimc->vid_cap.refcnt == 1) { 493 return ret;
498 ret = fimc_pipeline_initialize(&fimc->pipeline, 494
499 &fimc->vid_cap.vfd->entity, true); 495 ret = v4l2_fh_open(file);
500 if (ret < 0) { 496 if (ret)
501 dev_err(&fimc->pdev->dev, 497 return ret;
502 "Video pipeline initialization failed\n"); 498
503 clear_bit(ST_CAPT_BUSY, &fimc->state); 499 if (++fimc->vid_cap.refcnt != 1)
504 pm_runtime_put_sync(&fimc->pdev->dev); 500 return 0;
505 fimc->vid_cap.refcnt--;
506 v4l2_fh_release(file);
507 return ret;
508 }
509 ret = fimc_capture_ctrls_create(fimc);
510 501
511 if (!ret && !fimc->vid_cap.user_subdev_api) 502 ret = fimc_pipeline_initialize(&fimc->pipeline,
512 ret = fimc_capture_set_default_format(fimc); 503 &fimc->vid_cap.vfd->entity, true);
504 if (ret < 0) {
505 clear_bit(ST_CAPT_BUSY, &fimc->state);
506 pm_runtime_put_sync(&fimc->pdev->dev);
507 fimc->vid_cap.refcnt--;
508 v4l2_fh_release(file);
509 return ret;
513 } 510 }
511 ret = fimc_capture_ctrls_create(fimc);
512
513 if (!ret && !fimc->vid_cap.user_subdev_api)
514 ret = fimc_capture_set_default_format(fimc);
515
514 return ret; 516 return ret;
515} 517}
516 518
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.c b/drivers/media/video/s5p-fimc/fimc-lite.c
index 400d701aef04..bbe93e4a8731 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite.c
+++ b/drivers/media/video/s5p-fimc/fimc-lite.c
@@ -451,21 +451,23 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
451static int fimc_lite_open(struct file *file) 451static int fimc_lite_open(struct file *file)
452{ 452{
453 struct fimc_lite *fimc = video_drvdata(file); 453 struct fimc_lite *fimc = video_drvdata(file);
454 int ret = v4l2_fh_open(file); 454 int ret;
455
456 if (ret)
457 return ret;
458 455
459 set_bit(ST_FLITE_IN_USE, &fimc->state); 456 set_bit(ST_FLITE_IN_USE, &fimc->state);
460 pm_runtime_get_sync(&fimc->pdev->dev); 457 ret = pm_runtime_get_sync(&fimc->pdev->dev);
458 if (ret < 0)
459 return ret;
461 460
462 if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA) 461 if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA)
462 return 0;
463
464 ret = v4l2_fh_open(file);
465 if (ret < 0)
463 return ret; 466 return ret;
464 467
465 ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity, 468 ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity,
466 true); 469 true);
467 if (ret < 0) { 470 if (ret < 0) {
468 v4l2_err(fimc->vfd, "Video pipeline initialization failed\n");
469 pm_runtime_put_sync(&fimc->pdev->dev); 471 pm_runtime_put_sync(&fimc->pdev->dev);
470 fimc->ref_count--; 472 fimc->ref_count--;
471 v4l2_fh_release(file); 473 v4l2_fh_release(file);
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index dffe4da5eaa0..52cef4865423 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -741,8 +741,8 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
741} 741}
742 742
743static int __fimc_md_set_camclk(struct fimc_md *fmd, 743static int __fimc_md_set_camclk(struct fimc_md *fmd,
744 struct fimc_sensor_info *s_info, 744 struct fimc_sensor_info *s_info,
745 bool on) 745 bool on)
746{ 746{
747 struct s5p_fimc_isp_info *pdata = s_info->pdata; 747 struct s5p_fimc_isp_info *pdata = s_info->pdata;
748 struct fimc_camclk_info *camclk; 748 struct fimc_camclk_info *camclk;
@@ -751,12 +751,10 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
751 if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL) 751 if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
752 return -EINVAL; 752 return -EINVAL;
753 753
754 if (s_info->clk_on == on)
755 return 0;
756 camclk = &fmd->camclk[pdata->clk_id]; 754 camclk = &fmd->camclk[pdata->clk_id];
757 755
758 dbg("camclk %d, f: %lu, clk: %p, on: %d", 756 dbg("camclk %d, f: %lu, use_count: %d, on: %d",
759 pdata->clk_id, pdata->clk_frequency, camclk, on); 757 pdata->clk_id, pdata->clk_frequency, camclk->use_count, on);
760 758
761 if (on) { 759 if (on) {
762 if (camclk->use_count > 0 && 760 if (camclk->use_count > 0 &&
@@ -767,11 +765,9 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
767 clk_set_rate(camclk->clock, pdata->clk_frequency); 765 clk_set_rate(camclk->clock, pdata->clk_frequency);
768 camclk->frequency = pdata->clk_frequency; 766 camclk->frequency = pdata->clk_frequency;
769 ret = clk_enable(camclk->clock); 767 ret = clk_enable(camclk->clock);
768 dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
769 clk_get_rate(camclk->clock));
770 } 770 }
771 s_info->clk_on = 1;
772 dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
773 clk_get_rate(camclk->clock));
774
775 return ret; 771 return ret;
776 } 772 }
777 773
@@ -780,7 +776,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
780 776
781 if (--camclk->use_count == 0) { 777 if (--camclk->use_count == 0) {
782 clk_disable(camclk->clock); 778 clk_disable(camclk->clock);
783 s_info->clk_on = 0;
784 dbg("Disabled camclk %d", pdata->clk_id); 779 dbg("Disabled camclk %d", pdata->clk_id);
785 } 780 }
786 return ret; 781 return ret;
@@ -796,8 +791,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
796 * devices to which sensors can be attached, either directly or through 791 * devices to which sensors can be attached, either directly or through
797 * the MIPI CSI receiver. The clock is allowed here to be used by 792 * the MIPI CSI receiver. The clock is allowed here to be used by
798 * multiple sensors concurrently if they use same frequency. 793 * multiple sensors concurrently if they use same frequency.
799 * The per sensor subdev clk_on attribute helps to synchronize accesses
800 * to the sclk_cam clocks from the video and media device nodes.
801 * This function should only be called when the graph mutex is held. 794 * This function should only be called when the graph mutex is held.
802 */ 795 */
803int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) 796int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h
index 3b8a3492a176..1f5dbaff5442 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.h
@@ -47,7 +47,6 @@ struct fimc_camclk_info {
47 * @pdata: sensor's atrributes passed as media device's platform data 47 * @pdata: sensor's atrributes passed as media device's platform data
48 * @subdev: image sensor v4l2 subdev 48 * @subdev: image sensor v4l2 subdev
49 * @host: fimc device the sensor is currently linked to 49 * @host: fimc device the sensor is currently linked to
50 * @clk_on: sclk_cam clock's state associated with this subdev
51 * 50 *
52 * This data structure applies to image sensor and the writeback subdevs. 51 * This data structure applies to image sensor and the writeback subdevs.
53 */ 52 */
@@ -55,7 +54,6 @@ struct fimc_sensor_info {
55 struct s5p_fimc_isp_info *pdata; 54 struct s5p_fimc_isp_info *pdata;
56 struct v4l2_subdev *subdev; 55 struct v4l2_subdev *subdev;
57 struct fimc_dev *host; 56 struct fimc_dev *host;
58 bool clk_on;
59}; 57};
60 58
61/** 59/**