diff options
-rw-r--r-- | drivers/media/video/omap3isp/isp.c | 27 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/isp.h | 3 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispvideo.c | 4 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispvideo.h | 2 |
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 | */ |
92 | struct isp_pipeline { | 93 | struct 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; |