aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-11-18 09:28:24 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-08 12:50:29 -0400
commit1567bb7dcc6a232693143fdbe3b89791f20890ac (patch)
tree5366c345c2bd20bccf09a4b77296763eef28b693 /drivers
parent4742c82ed90d0f8c82639750dcfe481e61d883a4 (diff)
[media] omap3isp: Prevent pipelines that contain a crashed entity from starting
The OMAP3 ISP preview engine will violate the L4 bus protocol if we try to write some of its internal registers after it failed to stop properly. This generates an external abort on non-linefetch fault, triggering a fatal kernel oops. We can't always prevent preview engine stop failures (they can for instance be caused by a sensor crash), but we can improve the system reliability by refusing to start streaming on a pipeline that contains the preview engine if it failed to stop. The driver will then eventually reset the ISP (when all applications will have closed their file handles related to OMAP3 ISP device nodes), making the ISP usable again. Fixes: NB#291334 - camera: Recover gracefully from ISP crash instead of oopsing Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> Reviewed-by: Phil Carmody <ext-phil.2.carmody@nokia.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/omap3isp/isp.c27
-rw-r--r--drivers/media/video/omap3isp/isp.h3
-rw-r--r--drivers/media/video/omap3isp/ispvideo.c4
-rw-r--r--drivers/media/video/omap3isp/ispvideo.h2
4 files changed, 29 insertions, 7 deletions
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 12d5f923e1d0..3db8583497ee 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -739,6 +739,17 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
739 unsigned long flags; 739 unsigned long flags;
740 int ret; 740 int ret;
741 741
742 /* If the preview engine crashed it might not respond to read/write
743 * operations on the L4 bus. This would result in a bus fault and a
744 * kernel oops. Refuse to start streaming in that case. This check must
745 * be performed before the loop below to avoid starting entities if the
746 * pipeline won't start anyway (those entities would then likely fail to
747 * stop, making the problem worse).
748 */
749 if ((pipe->entities & isp->crashed) &
750 (1U << isp->isp_prev.subdev.entity.id))
751 return -EIO;
752
742 spin_lock_irqsave(&pipe->lock, flags); 753 spin_lock_irqsave(&pipe->lock, flags);
743 pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT); 754 pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
744 spin_unlock_irqrestore(&pipe->lock, flags); 755 spin_unlock_irqrestore(&pipe->lock, flags);
@@ -879,13 +890,15 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
879 890
880 if (ret) { 891 if (ret) {
881 dev_info(isp->dev, "Unable to stop %s\n", subdev->name); 892 dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
893 /* If the entity failed to stopped, assume it has
894 * crashed. Mark it as such, the ISP will be reset when
895 * applications will release it.
896 */
897 isp->crashed |= 1U << subdev->entity.id;
882 failure = -ETIMEDOUT; 898 failure = -ETIMEDOUT;
883 } 899 }
884 } 900 }
885 901
886 if (failure < 0)
887 isp->needs_reset = true;
888
889 return failure; 902 return failure;
890} 903}
891 904
@@ -1069,6 +1082,7 @@ static int isp_reset(struct isp_device *isp)
1069 udelay(1); 1082 udelay(1);
1070 } 1083 }
1071 1084
1085 isp->crashed = 0;
1072 return 0; 1086 return 0;
1073} 1087}
1074 1088
@@ -1496,10 +1510,11 @@ void omap3isp_put(struct isp_device *isp)
1496 if (--isp->ref_count == 0) { 1510 if (--isp->ref_count == 0) {
1497 isp_disable_interrupts(isp); 1511 isp_disable_interrupts(isp);
1498 isp_save_ctx(isp); 1512 isp_save_ctx(isp);
1499 if (isp->needs_reset) { 1513 /* Reset the ISP if an entity has failed to stop. This is the
1514 * only way to recover from such conditions.
1515 */
1516 if (isp->crashed)
1500 isp_reset(isp); 1517 isp_reset(isp);
1501 isp->needs_reset = false;
1502 }
1503 isp_disable_clocks(isp); 1518 isp_disable_clocks(isp);
1504 } 1519 }
1505 mutex_unlock(&isp->isp_mutex); 1520 mutex_unlock(&isp->isp_mutex);
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index d96603eb0d17..f8d1f100fc19 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -145,6 +145,7 @@ struct isp_platform_callback {
145 * @raw_dmamask: Raw DMA mask 145 * @raw_dmamask: Raw DMA mask
146 * @stat_lock: Spinlock for handling statistics 146 * @stat_lock: Spinlock for handling statistics
147 * @isp_mutex: Mutex for serializing requests to ISP. 147 * @isp_mutex: Mutex for serializing requests to ISP.
148 * @crashed: Bitmask of crashed entities (indexed by entity ID)
148 * @has_context: Context has been saved at least once and can be restored. 149 * @has_context: Context has been saved at least once and can be restored.
149 * @ref_count: Reference count for handling multiple ISP requests. 150 * @ref_count: Reference count for handling multiple ISP requests.
150 * @cam_ick: Pointer to camera interface clock structure. 151 * @cam_ick: Pointer to camera interface clock structure.
@@ -184,7 +185,7 @@ struct isp_device {
184 /* ISP Obj */ 185 /* ISP Obj */
185 spinlock_t stat_lock; /* common lock for statistic drivers */ 186 spinlock_t stat_lock; /* common lock for statistic drivers */
186 struct mutex isp_mutex; /* For handling ref_count field */ 187 struct mutex isp_mutex; /* For handling ref_count field */
187 bool needs_reset; 188 u32 crashed;
188 int has_context; 189 int has_context;
189 int ref_count; 190 int ref_count;
190 unsigned int autoidle; 191 unsigned int autoidle;
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index b02070057724..2107d99d523a 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -292,6 +292,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
292 int ret; 292 int ret;
293 293
294 pipe->max_rate = pipe->l3_ick; 294 pipe->max_rate = pipe->l3_ick;
295 pipe->entities = 0;
295 296
296 subdev = isp_video_remote_subdev(pipe->output, NULL); 297 subdev = isp_video_remote_subdev(pipe->output, NULL);
297 if (subdev == NULL) 298 if (subdev == NULL)
@@ -299,6 +300,9 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
299 300
300 while (1) { 301 while (1) {
301 unsigned int shifter_link; 302 unsigned int shifter_link;
303
304 pipe->entities |= 1U << subdev->entity.id;
305
302 /* Retrieve the sink format */ 306 /* Retrieve the sink format */
303 pad = &subdev->entity.pads[0]; 307 pad = &subdev->entity.pads[0];
304 if (!(pad->flags & MEDIA_PAD_FL_SINK)) 308 if (!(pad->flags & MEDIA_PAD_FL_SINK))
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
index d91bdb919be0..c9187cbc3557 100644
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ b/drivers/media/video/omap3isp/ispvideo.h
@@ -88,6 +88,7 @@ enum isp_pipeline_state {
88/* 88/*
89 * struct isp_pipeline - An ISP hardware pipeline 89 * struct isp_pipeline - An ISP hardware pipeline
90 * @error: A hardware error occurred during capture 90 * @error: A hardware error occurred during capture
91 * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
91 */ 92 */
92struct isp_pipeline { 93struct isp_pipeline {
93 struct media_pipeline pipe; 94 struct media_pipeline pipe;
@@ -96,6 +97,7 @@ struct isp_pipeline {
96 enum isp_pipeline_stream_state stream_state; 97 enum isp_pipeline_stream_state stream_state;
97 struct isp_video *input; 98 struct isp_video *input;
98 struct isp_video *output; 99 struct isp_video *output;
100 u32 entities;
99 unsigned long l3_ick; 101 unsigned long l3_ick;
100 unsigned int max_rate; 102 unsigned int max_rate;
101 atomic_t frame_number; 103 atomic_t frame_number;