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>
This commit is contained in:
Ashwini Rao 2016-01-21 14:59:14 -08:00 committed by Gerrit - the friendly Code Review server
parent ea445a93a0
commit 034f436b68
3 changed files with 88 additions and 0 deletions

View file

@ -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;

View file

@ -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__ */

View file

@ -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);