From 034f436b68048a5860de3f0df3fbf73f348a8df8 Mon Sep 17 00:00:00 2001 From: Ashwini Rao Date: Thu, 21 Jan 2016 14:59:14 -0800 Subject: [PATCH] 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 --- .../platform/msm/camera_v2/fd/msm_fd_dev.c | 79 +++++++++++++++++++ .../platform/msm/camera_v2/fd/msm_fd_dev.h | 5 ++ .../platform/msm/camera_v2/fd/msm_fd_hw.c | 4 + 3 files changed, 88 insertions(+) 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. */ @@ -328,6 +330,68 @@ static struct vb2_mem_ops msm_fd_vb2_mem_ops = { .put_userptr = msm_fd_put_userptr, }; +/* + * 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 #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);