summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAshwini Rao <ashwinik@codeaurora.org>2016-01-21 14:59:14 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-12-12 17:02:40 -0800
commit034f436b68048a5860de3f0df3fbf73f348a8df8 (patch)
tree61079bb5320dc1094044bebe3f1e70c9ce88c43d
parentea445a93a03fe68f643e18cfc7c87c8c1c28c225 (diff)
msm: camera: fd: Add CPP VBIF error handling
On detecting a VBIF hang, reset the VBIF and FD core and if there is an active buffer, queue back the active buffer and start processing again. CRs-Fixed: 961394 Change-Id: I1ed035c8a8efb20d31da9556c5d5b810f81c44d2 Signed-off-by: Ashwini Rao <ashwinik@codeaurora.org>
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c79
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h5
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c4
3 files changed, 88 insertions, 0 deletions
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
index a56e42dc1c6f..1cfb7a3dfa00 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
@@ -266,8 +266,10 @@ static void msm_fd_stop_streaming(struct vb2_queue *q)
{
struct fd_ctx *ctx = vb2_get_drv_priv(q);
+ mutex_lock(&ctx->fd_device->recovery_lock);
msm_fd_hw_remove_buffers_from_queue(ctx->fd_device, q);
msm_fd_hw_put(ctx->fd_device);
+ mutex_unlock(&ctx->fd_device->recovery_lock);
}
/* Videobuf2 queue callbacks. */
@@ -329,6 +331,68 @@ static struct vb2_mem_ops msm_fd_vb2_mem_ops = {
};
/*
+ * msm_fd_vbif_error_handler - FD VBIF Error handler
+ * @handle: FD Device handle
+ * @error: CPP-VBIF Error code
+ */
+static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
+{
+ struct fd_ctx *ctx;
+ struct msm_fd_device *fd;
+ struct msm_fd_buffer *active_buf;
+ int ret;
+
+ if (handle == NULL)
+ return 0;
+
+ ctx = (struct fd_ctx *)handle;
+ fd = (struct msm_fd_device *)ctx->fd_device;
+
+ if (error == CPP_VBIF_ERROR_HANG) {
+ mutex_lock(&fd->recovery_lock);
+ dev_err(fd->dev, "Handling FD VBIF Hang\n");
+ if (fd->state != MSM_FD_DEVICE_RUNNING) {
+ dev_err(fd->dev, "FD is not FD_DEVICE_RUNNING, %d\n",
+ fd->state);
+ mutex_unlock(&fd->recovery_lock);
+ return 0;
+ }
+ fd->recovery_mode = 1;
+
+ /* Halt and reset */
+ msm_fd_hw_put(fd);
+ msm_fd_hw_get(fd, ctx->settings.speed);
+
+ /* Get active buffer */
+ active_buf = msm_fd_hw_get_active_buffer(fd);
+
+ if (active_buf == NULL) {
+ dev_dbg(fd->dev, "no active buffer, return\n");
+ fd->recovery_mode = 0;
+ mutex_unlock(&fd->recovery_lock);
+ return 0;
+ }
+
+ dev_dbg(fd->dev, "Active Buffer present.. Start re-schedule\n");
+
+ /* Queue the buffer again */
+ msm_fd_hw_add_buffer(fd, active_buf);
+
+ /* Schedule and restart */
+ ret = msm_fd_hw_schedule_next_buffer(fd);
+ if (ret) {
+ dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n");
+ fd->recovery_mode = 0;
+ mutex_unlock(&fd->recovery_lock);
+ return ret;
+ }
+ dev_dbg(fd->dev, "Restarted FD after VBIF HAng\n");
+ mutex_unlock(&fd->recovery_lock);
+ }
+ return 0;
+}
+
+/*
* msm_fd_open - Fd device open method.
* @file: Pointer to file struct.
*/
@@ -391,6 +455,10 @@ static int msm_fd_open(struct file *file)
goto error_ahb_config;
}
+ /* Register with CPP VBIF error handler */
+ msm_cpp_vbif_register_error_handler((void *)ctx,
+ VBIF_CLIENT_FD, msm_fd_vbif_error_handler);
+
return 0;
error_ahb_config:
@@ -412,6 +480,10 @@ static int msm_fd_release(struct file *file)
{
struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
+ /* Un-register with CPP VBIF error handler */
+ msm_cpp_vbif_register_error_handler((void *)ctx,
+ VBIF_CLIENT_FD, NULL);
+
vb2_queue_release(&ctx->vb2_q);
vfree(ctx->stats);
@@ -1176,6 +1248,12 @@ static void msm_fd_wq_handler(struct work_struct *work)
/* Stats are ready, set correct frame id */
atomic_set(&stats->frame_id, ctx->sequence);
+ /* If Recovery mode is on, we got IRQ after recovery, reset it */
+ if (fd->recovery_mode) {
+ fd->recovery_mode = 0;
+ dev_dbg(fd->dev, "Got IRQ after Recovery\n");
+ }
+
/* We have the data from fd hw, we can start next processing */
msm_fd_hw_schedule_next_buffer(fd);
@@ -1213,6 +1291,7 @@ static int fd_probe(struct platform_device *pdev)
mutex_init(&fd->lock);
spin_lock_init(&fd->slock);
+ mutex_init(&fd->recovery_lock);
init_completion(&fd->hw_halt_completion);
INIT_LIST_HEAD(&fd->buf_queue);
fd->pdev = pdev;
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
index b96c33b3fd07..e7dcb383d09f 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
@@ -23,6 +23,8 @@
#include <linux/msm_ion.h>
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
+#include "msm_cpp.h"
+
/* Maximum number of result buffers */
#define MSM_FD_MAX_RESULT_BUFS 5
/* Max number of clocks defined in device tree */
@@ -214,12 +216,14 @@ enum msm_fd_mem_resources {
* @work_queue: Pointer to FD device IRQ bottom half workqueue.
* @work: IRQ bottom half work struct.
* @hw_halt_completion: Completes when face detection hw halt completes.
+ * @recovery_mode: Indicates if FD is in recovery mode
*/
struct msm_fd_device {
u32 hw_revision;
struct mutex lock;
spinlock_t slock;
+ struct mutex recovery_lock;
int ref_count;
int irq_num;
@@ -248,6 +252,7 @@ struct msm_fd_device {
struct workqueue_struct *work_queue;
struct work_struct work;
struct completion hw_halt_completion;
+ int recovery_mode;
};
#endif /* __MSM_FD_DEV_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
index 17c51383682b..c5efb1153204 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
@@ -1058,6 +1058,8 @@ static int msm_fd_hw_enable(struct msm_fd_device *fd,
msm_fd_hw_set_direction_angle(fd, buffer->settings.direction_index,
buffer->settings.angle_index);
msm_fd_hw_run(fd);
+ if (fd->recovery_mode)
+ dev_err(fd->dev, "Scheduled buffer in recovery mode\n");
return 1;
}
@@ -1260,6 +1262,8 @@ int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd)
}
} else {
fd->state = MSM_FD_DEVICE_IDLE;
+ if (fd->recovery_mode)
+ dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n");
}
spin_unlock(&fd->slock);