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:
parent
ea445a93a0
commit
034f436b68
3 changed files with 88 additions and 0 deletions
|
@ -266,8 +266,10 @@ static void msm_fd_stop_streaming(struct vb2_queue *q)
|
||||||
{
|
{
|
||||||
struct fd_ctx *ctx = vb2_get_drv_priv(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_remove_buffers_from_queue(ctx->fd_device, q);
|
||||||
msm_fd_hw_put(ctx->fd_device);
|
msm_fd_hw_put(ctx->fd_device);
|
||||||
|
mutex_unlock(&ctx->fd_device->recovery_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Videobuf2 queue callbacks. */
|
/* Videobuf2 queue callbacks. */
|
||||||
|
@ -328,6 +330,68 @@ static struct vb2_mem_ops msm_fd_vb2_mem_ops = {
|
||||||
.put_userptr = msm_fd_put_userptr,
|
.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.
|
* msm_fd_open - Fd device open method.
|
||||||
* @file: Pointer to file struct.
|
* @file: Pointer to file struct.
|
||||||
|
@ -391,6 +455,10 @@ static int msm_fd_open(struct file *file)
|
||||||
goto error_ahb_config;
|
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;
|
return 0;
|
||||||
|
|
||||||
error_ahb_config:
|
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);
|
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);
|
vb2_queue_release(&ctx->vb2_q);
|
||||||
|
|
||||||
vfree(ctx->stats);
|
vfree(ctx->stats);
|
||||||
|
@ -1176,6 +1248,12 @@ static void msm_fd_wq_handler(struct work_struct *work)
|
||||||
/* Stats are ready, set correct frame id */
|
/* Stats are ready, set correct frame id */
|
||||||
atomic_set(&stats->frame_id, ctx->sequence);
|
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 */
|
/* We have the data from fd hw, we can start next processing */
|
||||||
msm_fd_hw_schedule_next_buffer(fd);
|
msm_fd_hw_schedule_next_buffer(fd);
|
||||||
|
|
||||||
|
@ -1213,6 +1291,7 @@ static int fd_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
mutex_init(&fd->lock);
|
mutex_init(&fd->lock);
|
||||||
spin_lock_init(&fd->slock);
|
spin_lock_init(&fd->slock);
|
||||||
|
mutex_init(&fd->recovery_lock);
|
||||||
init_completion(&fd->hw_halt_completion);
|
init_completion(&fd->hw_halt_completion);
|
||||||
INIT_LIST_HEAD(&fd->buf_queue);
|
INIT_LIST_HEAD(&fd->buf_queue);
|
||||||
fd->pdev = pdev;
|
fd->pdev = pdev;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <linux/msm_ion.h>
|
#include <linux/msm_ion.h>
|
||||||
#include "cam_soc_api.h"
|
#include "cam_soc_api.h"
|
||||||
#include "cam_hw_ops.h"
|
#include "cam_hw_ops.h"
|
||||||
|
#include "msm_cpp.h"
|
||||||
|
|
||||||
/* Maximum number of result buffers */
|
/* Maximum number of result buffers */
|
||||||
#define MSM_FD_MAX_RESULT_BUFS 5
|
#define MSM_FD_MAX_RESULT_BUFS 5
|
||||||
/* Max number of clocks defined in device tree */
|
/* 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_queue: Pointer to FD device IRQ bottom half workqueue.
|
||||||
* @work: IRQ bottom half work struct.
|
* @work: IRQ bottom half work struct.
|
||||||
* @hw_halt_completion: Completes when face detection hw halt completes.
|
* @hw_halt_completion: Completes when face detection hw halt completes.
|
||||||
|
* @recovery_mode: Indicates if FD is in recovery mode
|
||||||
*/
|
*/
|
||||||
struct msm_fd_device {
|
struct msm_fd_device {
|
||||||
u32 hw_revision;
|
u32 hw_revision;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
spinlock_t slock;
|
spinlock_t slock;
|
||||||
|
struct mutex recovery_lock;
|
||||||
int ref_count;
|
int ref_count;
|
||||||
|
|
||||||
int irq_num;
|
int irq_num;
|
||||||
|
@ -248,6 +252,7 @@ struct msm_fd_device {
|
||||||
struct workqueue_struct *work_queue;
|
struct workqueue_struct *work_queue;
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
struct completion hw_halt_completion;
|
struct completion hw_halt_completion;
|
||||||
|
int recovery_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __MSM_FD_DEV_H__ */
|
#endif /* __MSM_FD_DEV_H__ */
|
||||||
|
|
|
@ -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,
|
msm_fd_hw_set_direction_angle(fd, buffer->settings.direction_index,
|
||||||
buffer->settings.angle_index);
|
buffer->settings.angle_index);
|
||||||
msm_fd_hw_run(fd);
|
msm_fd_hw_run(fd);
|
||||||
|
if (fd->recovery_mode)
|
||||||
|
dev_err(fd->dev, "Scheduled buffer in recovery mode\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,6 +1262,8 @@ int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fd->state = MSM_FD_DEVICE_IDLE;
|
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);
|
spin_unlock(&fd->slock);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue