diff options
-rw-r--r-- | drivers/media/platform/omap3isp/isp.c | 36 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/isp.h | 2 |
2 files changed, 24 insertions, 14 deletions
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 7e09c1dd137a..5807185262fe 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
@@ -873,15 +873,12 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, | |||
873 | unsigned long flags; | 873 | unsigned long flags; |
874 | int ret; | 874 | int ret; |
875 | 875 | ||
876 | /* If the preview engine crashed it might not respond to read/write | 876 | /* Refuse to start streaming if an entity included in the pipeline has |
877 | * operations on the L4 bus. This would result in a bus fault and a | 877 | * crashed. This check must be performed before the loop below to avoid |
878 | * kernel oops. Refuse to start streaming in that case. This check must | 878 | * starting entities if the pipeline won't start anyway (those entities |
879 | * be performed before the loop below to avoid starting entities if the | 879 | * would then likely fail to stop, making the problem worse). |
880 | * pipeline won't start anyway (those entities would then likely fail to | ||
881 | * stop, making the problem worse). | ||
882 | */ | 880 | */ |
883 | if ((pipe->entities & isp->crashed) & | 881 | if (pipe->entities & isp->crashed) |
884 | (1U << isp->isp_prev.subdev.entity.id)) | ||
885 | return -EIO; | 882 | return -EIO; |
886 | 883 | ||
887 | spin_lock_irqsave(&pipe->lock, flags); | 884 | spin_lock_irqsave(&pipe->lock, flags); |
@@ -1014,13 +1011,23 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) | |||
1014 | else | 1011 | else |
1015 | ret = 0; | 1012 | ret = 0; |
1016 | 1013 | ||
1014 | /* Handle stop failures. An entity that fails to stop can | ||
1015 | * usually just be restarted. Flag the stop failure nonetheless | ||
1016 | * to trigger an ISP reset the next time the device is released, | ||
1017 | * just in case. | ||
1018 | * | ||
1019 | * The preview engine is a special case. A failure to stop can | ||
1020 | * mean a hardware crash. When that happens the preview engine | ||
1021 | * won't respond to read/write operations on the L4 bus anymore, | ||
1022 | * resulting in a bus fault and a kernel oops next time it gets | ||
1023 | * accessed. Mark it as crashed to prevent pipelines including | ||
1024 | * it from being started. | ||
1025 | */ | ||
1017 | if (ret) { | 1026 | if (ret) { |
1018 | dev_info(isp->dev, "Unable to stop %s\n", subdev->name); | 1027 | dev_info(isp->dev, "Unable to stop %s\n", subdev->name); |
1019 | /* If the entity failed to stopped, assume it has | 1028 | isp->stop_failure = true; |
1020 | * crashed. Mark it as such, the ISP will be reset when | 1029 | if (subdev == &isp->isp_prev.subdev) |
1021 | * applications will release it. | 1030 | isp->crashed |= 1U << subdev->entity.id; |
1022 | */ | ||
1023 | isp->crashed |= 1U << subdev->entity.id; | ||
1024 | failure = -ETIMEDOUT; | 1031 | failure = -ETIMEDOUT; |
1025 | } | 1032 | } |
1026 | } | 1033 | } |
@@ -1225,6 +1232,7 @@ static int isp_reset(struct isp_device *isp) | |||
1225 | udelay(1); | 1232 | udelay(1); |
1226 | } | 1233 | } |
1227 | 1234 | ||
1235 | isp->stop_failure = false; | ||
1228 | isp->crashed = 0; | 1236 | isp->crashed = 0; |
1229 | return 0; | 1237 | return 0; |
1230 | } | 1238 | } |
@@ -1636,7 +1644,7 @@ void omap3isp_put(struct isp_device *isp) | |||
1636 | /* Reset the ISP if an entity has failed to stop. This is the | 1644 | /* Reset the ISP if an entity has failed to stop. This is the |
1637 | * only way to recover from such conditions. | 1645 | * only way to recover from such conditions. |
1638 | */ | 1646 | */ |
1639 | if (isp->crashed) | 1647 | if (isp->crashed || isp->stop_failure) |
1640 | isp_reset(isp); | 1648 | isp_reset(isp); |
1641 | isp_disable_clocks(isp); | 1649 | isp_disable_clocks(isp); |
1642 | } | 1650 | } |
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 5b91f8619886..081f5ec5a663 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h | |||
@@ -154,6 +154,7 @@ struct isp_xclk { | |||
154 | * regions. | 154 | * regions. |
155 | * @stat_lock: Spinlock for handling statistics | 155 | * @stat_lock: Spinlock for handling statistics |
156 | * @isp_mutex: Mutex for serializing requests to ISP. | 156 | * @isp_mutex: Mutex for serializing requests to ISP. |
157 | * @stop_failure: Indicates that an entity failed to stop. | ||
157 | * @crashed: Bitmask of crashed entities (indexed by entity ID) | 158 | * @crashed: Bitmask of crashed entities (indexed by entity ID) |
158 | * @has_context: Context has been saved at least once and can be restored. | 159 | * @has_context: Context has been saved at least once and can be restored. |
159 | * @ref_count: Reference count for handling multiple ISP requests. | 160 | * @ref_count: Reference count for handling multiple ISP requests. |
@@ -191,6 +192,7 @@ struct isp_device { | |||
191 | /* ISP Obj */ | 192 | /* ISP Obj */ |
192 | spinlock_t stat_lock; /* common lock for statistic drivers */ | 193 | spinlock_t stat_lock; /* common lock for statistic drivers */ |
193 | struct mutex isp_mutex; /* For handling ref_count field */ | 194 | struct mutex isp_mutex; /* For handling ref_count field */ |
195 | bool stop_failure; | ||
194 | u32 crashed; | 196 | u32 crashed; |
195 | int has_context; | 197 | int has_context; |
196 | int ref_count; | 198 | int ref_count; |