msm: isp: Handle ping pong mismatch error
Pingpong mismatch happens when there is a scheduling delay. Recover from ping pong mismatch and print the debug information into trace buffer. Change-Id: Ib667a6e1368897837c1d0fe55487e69b521b1179 Signed-off-by: Abhishek Kondaveeti <akondave@codeaurora.org>
This commit is contained in:
parent
55e8426a19
commit
01f5d39b2a
14 changed files with 395 additions and 21 deletions
|
@ -500,6 +500,10 @@ static int vfe_probe(struct platform_device *pdev)
|
|||
memset(&vfe_common_data, 0, sizeof(vfe_common_data));
|
||||
mutex_init(&vfe_common_data.vfe_common_mutex);
|
||||
spin_lock_init(&vfe_common_data.common_dev_data_lock);
|
||||
spin_lock_init(&vfe_common_data.vfe_irq_dump.
|
||||
common_dev_irq_dump_lock);
|
||||
spin_lock_init(&vfe_common_data.vfe_irq_dump.
|
||||
common_dev_tasklet_dump_lock);
|
||||
for (i = 0; i < (VFE_AXI_SRC_MAX * MAX_VFE); i++)
|
||||
spin_lock_init(&(vfe_common_data.streams[i].lock));
|
||||
for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++)
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
#define MAX_BUFFERS_IN_HW 2
|
||||
|
||||
#define MAX_VFE 2
|
||||
#define MAX_VFE_IRQ_DEBUG_DUMP_SIZE 10
|
||||
#define MAX_RECOVERY_THRESHOLD 5
|
||||
|
||||
struct vfe_device;
|
||||
struct msm_vfe_axi_stream;
|
||||
|
@ -133,6 +135,8 @@ struct msm_isp_timestamp {
|
|||
};
|
||||
|
||||
struct msm_vfe_irq_ops {
|
||||
void (*read_and_clear_irq_status)(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1);
|
||||
void (*read_irq_status)(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1);
|
||||
void (*process_reg_update)(struct vfe_device *vfe_dev,
|
||||
|
@ -525,6 +529,7 @@ struct msm_vfe_axi_shared_data {
|
|||
uint16_t stream_handle_cnt;
|
||||
uint32_t event_mask;
|
||||
uint8_t enable_frameid_recovery;
|
||||
uint8_t recovery_count;
|
||||
};
|
||||
|
||||
struct msm_vfe_stats_hardware_info {
|
||||
|
@ -691,6 +696,26 @@ struct master_slave_resource_info {
|
|||
enum msm_vfe_dual_cam_sync_mode dual_sync_mode;
|
||||
};
|
||||
|
||||
struct msm_vfe_irq_debug_info {
|
||||
uint32_t vfe_id;
|
||||
struct msm_isp_timestamp ts;
|
||||
uint32_t core_id;
|
||||
uint32_t irq_status0[MAX_VFE];
|
||||
uint32_t irq_status1[MAX_VFE];
|
||||
uint32_t ping_pong_status[MAX_VFE];
|
||||
};
|
||||
|
||||
struct msm_vfe_irq_dump {
|
||||
spinlock_t common_dev_irq_dump_lock;
|
||||
spinlock_t common_dev_tasklet_dump_lock;
|
||||
uint8_t current_irq_index;
|
||||
uint8_t current_tasklet_index;
|
||||
struct msm_vfe_irq_debug_info
|
||||
irq_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE];
|
||||
struct msm_vfe_irq_debug_info
|
||||
tasklet_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE];
|
||||
};
|
||||
|
||||
struct msm_vfe_common_dev_data {
|
||||
spinlock_t common_dev_data_lock;
|
||||
struct dual_vfe_resource *dual_vfe_res;
|
||||
|
@ -698,6 +723,8 @@ struct msm_vfe_common_dev_data {
|
|||
struct msm_vfe_axi_stream streams[VFE_AXI_SRC_MAX * MAX_VFE];
|
||||
struct msm_vfe_stats_stream stats_streams[MSM_ISP_STATS_MAX * MAX_VFE];
|
||||
struct mutex vfe_common_mutex;
|
||||
/* Irq debug Info */
|
||||
struct msm_vfe_irq_dump vfe_irq_dump;
|
||||
};
|
||||
|
||||
struct msm_vfe_common_subdev {
|
||||
|
@ -790,8 +817,9 @@ struct vfe_device {
|
|||
/* irq info */
|
||||
uint32_t irq0_mask;
|
||||
uint32_t irq1_mask;
|
||||
|
||||
uint32_t bus_err_ign_mask;
|
||||
uint32_t recovery_irq0_mask;
|
||||
uint32_t recovery_irq1_mask;
|
||||
};
|
||||
|
||||
struct vfe_parent_device {
|
||||
|
|
|
@ -576,7 +576,7 @@ static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev)
|
|||
pr_err("%s: axi error\n", __func__);
|
||||
}
|
||||
|
||||
static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
|
||||
static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
|
||||
|
@ -594,6 +594,13 @@ static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
|
|||
msm_camera_io_r(vfe_dev->vfe_base + 0x7B4);
|
||||
}
|
||||
|
||||
static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
|
||||
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp *ts)
|
||||
|
@ -1423,6 +1430,8 @@ struct msm_vfe_hardware_info vfe32_hw_info = {
|
|||
.vfe_clk_idx = VFE32_CLK_IDX,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe32_read_and_clear_irq_status,
|
||||
.read_irq_status = msm_vfe32_read_irq_status,
|
||||
.process_camif_irq = msm_vfe32_process_camif_irq,
|
||||
.process_reset_irq = msm_vfe32_process_reset_irq,
|
||||
|
|
|
@ -566,7 +566,7 @@ static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev)
|
|||
msm_isp_update_last_overflow_ab_ib(vfe_dev);
|
||||
}
|
||||
|
||||
static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
|
||||
static void msm_vfe40_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
|
||||
|
@ -599,6 +599,13 @@ static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
|
|||
|
||||
}
|
||||
|
||||
static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
|
||||
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
|
||||
}
|
||||
|
||||
static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp *ts)
|
||||
|
@ -1770,7 +1777,8 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev,
|
|||
static void msm_vfe40_axi_restart(struct vfe_device *vfe_dev,
|
||||
uint32_t blocking, uint32_t enable_camif)
|
||||
{
|
||||
msm_vfe40_config_irq(vfe_dev, 0x800000E0, 0xFEFFFF7E,
|
||||
msm_vfe40_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
|
||||
vfe_dev->recovery_irq1_mask,
|
||||
MSM_ISP_IRQ_ENABLE);
|
||||
msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
|
||||
|
||||
|
@ -2198,6 +2206,8 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
|
|||
.min_ib = 12000000,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe40_read_and_clear_irq_status,
|
||||
.read_irq_status = msm_vfe40_read_irq_status,
|
||||
.process_camif_irq = msm_vfe40_process_input_irq,
|
||||
.process_reset_irq = msm_vfe40_process_reset_irq,
|
||||
|
|
|
@ -401,7 +401,7 @@ static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
|
||||
static void msm_vfe44_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
|
||||
|
@ -429,6 +429,13 @@ static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
|
|||
|
||||
}
|
||||
|
||||
static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
|
||||
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
|
||||
}
|
||||
|
||||
static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp *ts)
|
||||
|
@ -1341,8 +1348,8 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev,
|
|||
static void msm_vfe44_axi_restart(struct vfe_device *vfe_dev,
|
||||
uint32_t blocking, uint32_t enable_camif)
|
||||
{
|
||||
msm_vfe44_config_irq(vfe_dev, 0x800000E0, 0xFFFFFF7E,
|
||||
MSM_ISP_IRQ_ENABLE);
|
||||
msm_vfe44_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
|
||||
vfe_dev->recovery_irq1_mask, MSM_ISP_IRQ_ENABLE);
|
||||
msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
|
||||
|
||||
/* Start AXI */
|
||||
|
@ -1806,6 +1813,8 @@ struct msm_vfe_hardware_info vfe44_hw_info = {
|
|||
.min_ib = 100000000,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe44_read_and_clear_irq_status,
|
||||
.read_irq_status = msm_vfe44_read_irq_status,
|
||||
.process_camif_irq = msm_vfe44_process_input_irq,
|
||||
.process_reset_irq = msm_vfe44_process_reset_irq,
|
||||
|
|
|
@ -345,7 +345,7 @@ static void msm_vfe46_process_error_status(struct vfe_device *vfe_dev)
|
|||
pr_err("%s: status bf scale bus overflow\n", __func__);
|
||||
}
|
||||
|
||||
static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev,
|
||||
static void msm_vfe46_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
|
||||
|
@ -369,6 +369,13 @@ static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev,
|
|||
|
||||
}
|
||||
|
||||
static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
|
||||
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
|
||||
}
|
||||
|
||||
static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp *ts)
|
||||
|
@ -1406,7 +1413,8 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev,
|
|||
static void msm_vfe46_axi_restart(struct vfe_device *vfe_dev,
|
||||
uint32_t blocking, uint32_t enable_camif)
|
||||
{
|
||||
msm_vfe46_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E,
|
||||
msm_vfe46_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
|
||||
vfe_dev->recovery_irq1_mask,
|
||||
MSM_ISP_IRQ_ENABLE);
|
||||
msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x3CC);
|
||||
|
||||
|
@ -1882,6 +1890,8 @@ struct msm_vfe_hardware_info vfe46_hw_info = {
|
|||
.min_ib = 100000000,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe46_read_and_clear_irq_status,
|
||||
.read_irq_status = msm_vfe46_read_irq_status,
|
||||
.process_camif_irq = msm_vfe46_process_input_irq,
|
||||
.process_reset_irq = msm_vfe46_process_reset_irq,
|
||||
|
|
|
@ -559,7 +559,7 @@ void msm_vfe47_process_error_status(struct vfe_device *vfe_dev)
|
|||
pr_err("%s: status dsp error\n", __func__);
|
||||
}
|
||||
|
||||
void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
|
||||
void msm_vfe47_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
|
||||
|
@ -585,6 +585,13 @@ void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
|
|||
|
||||
}
|
||||
|
||||
void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
{
|
||||
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
|
||||
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
|
||||
}
|
||||
|
||||
void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp *ts)
|
||||
|
@ -1938,7 +1945,9 @@ void msm_vfe47_axi_restart(struct vfe_device *vfe_dev,
|
|||
uint32_t blocking, uint32_t enable_camif)
|
||||
{
|
||||
vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
|
||||
0x810000E0, 0xFFFFFF7E, MSM_ISP_IRQ_ENABLE);
|
||||
vfe_dev->recovery_irq0_mask,
|
||||
vfe_dev->recovery_irq1_mask,
|
||||
MSM_ISP_IRQ_ENABLE);
|
||||
/* Start AXI */
|
||||
msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x400);
|
||||
|
||||
|
@ -2795,7 +2804,8 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
|
|||
.min_ab = 100000000,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_irq_status = msm_vfe47_read_irq_status,
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe47_read_and_clear_irq_status,
|
||||
.process_camif_irq = msm_vfe47_process_input_irq,
|
||||
.process_reset_irq = msm_vfe47_process_reset_irq,
|
||||
.process_halt_irq = msm_vfe47_process_halt_irq,
|
||||
|
@ -2805,6 +2815,7 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
|
|||
.process_stats_irq = msm_isp_process_stats_irq,
|
||||
.process_epoch_irq = msm_vfe47_process_epoch_irq,
|
||||
.config_irq = msm_vfe47_config_irq,
|
||||
.read_irq_status = msm_vfe47_read_irq_status,
|
||||
},
|
||||
.axi_ops = {
|
||||
.reload_wm = msm_vfe47_axi_reload_wm,
|
||||
|
|
|
@ -30,6 +30,8 @@ enum msm_vfe47_stats_comp_idx {
|
|||
|
||||
extern struct msm_vfe_hardware_info vfe47_hw_info;
|
||||
|
||||
void msm_vfe47_read_and_clear_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1);
|
||||
void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1);
|
||||
void msm_vfe47_enable_camif_error(struct vfe_device *vfe_dev,
|
||||
|
|
|
@ -269,6 +269,8 @@ struct msm_vfe_hardware_info vfe48_hw_info = {
|
|||
.min_ab = 100000000,
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.read_and_clear_irq_status =
|
||||
msm_vfe47_read_and_clear_irq_status,
|
||||
.read_irq_status = msm_vfe47_read_irq_status,
|
||||
.process_camif_irq = msm_vfe47_process_input_irq,
|
||||
.process_reset_irq = msm_vfe47_process_reset_irq,
|
||||
|
|
|
@ -558,6 +558,7 @@ static int msm_isp_composite_irq(struct vfe_device *vfe_dev,
|
|||
{
|
||||
/* interrupt recv on same vfe w/o recv on other vfe */
|
||||
if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) {
|
||||
msm_isp_dump_ping_pong_mismatch(vfe_dev);
|
||||
pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n",
|
||||
__func__, irq, vfe_dev->pdev->id);
|
||||
return -EINVAL;
|
||||
|
@ -1604,7 +1605,23 @@ void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event)
|
|||
struct msm_isp_event_data error_event;
|
||||
struct msm_vfe_axi_halt_cmd halt_cmd;
|
||||
struct vfe_device *temp_dev = NULL;
|
||||
uint32_t irq_status0 = 0, irq_status1 = 0;
|
||||
|
||||
if (atomic_read(&vfe_dev->error_info.overflow_state) !=
|
||||
NO_OVERFLOW)
|
||||
/* Recovery is already in Progress */
|
||||
return;
|
||||
|
||||
if (event == ISP_EVENT_PING_PONG_MISMATCH &&
|
||||
vfe_dev->axi_data.recovery_count < MAX_RECOVERY_THRESHOLD) {
|
||||
pr_err("%s: ping pong mismatch on vfe%d recovery count %d\n",
|
||||
__func__, vfe_dev->pdev->id,
|
||||
vfe_dev->axi_data.recovery_count);
|
||||
msm_isp_process_overflow_irq(vfe_dev,
|
||||
&irq_status0, &irq_status1, 1);
|
||||
vfe_dev->axi_data.recovery_count++;
|
||||
return;
|
||||
}
|
||||
memset(&halt_cmd, 0, sizeof(struct msm_vfe_axi_halt_cmd));
|
||||
memset(&error_event, 0, sizeof(struct msm_isp_event_data));
|
||||
halt_cmd.stop_camif = 1;
|
||||
|
@ -3777,6 +3794,7 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
|
|||
(~(pingpong_status >>
|
||||
stream_info->wm[vfe_idx][i]) & 0x1)) {
|
||||
spin_unlock_irqrestore(&stream_info->lock, flags);
|
||||
msm_isp_dump_ping_pong_mismatch(vfe_dev);
|
||||
pr_err("%s: Write master ping pong mismatch. Status: 0x%x %x\n",
|
||||
__func__, pingpong_status,
|
||||
stream_info->stream_src);
|
||||
|
@ -3798,7 +3816,7 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
|
|||
spin_unlock_irqrestore(&stream_info->lock, flags);
|
||||
if (rc < 0)
|
||||
msm_isp_halt_send_error(vfe_dev,
|
||||
ISP_EVENT_BUF_FATAL_ERROR);
|
||||
ISP_EVENT_PING_PONG_MISMATCH);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
|
|||
spin_unlock_irqrestore(&stream_info->lock, flags);
|
||||
if (rc < 0)
|
||||
msm_isp_halt_send_error(vfe_dev,
|
||||
ISP_EVENT_BUF_FATAL_ERROR);
|
||||
ISP_EVENT_PING_PONG_MISMATCH);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "msm_camera_io_util.h"
|
||||
#include "cam_smmu_api.h"
|
||||
#include "msm_isp48.h"
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace/events/msm_cam.h"
|
||||
|
||||
|
||||
#define MAX_ISP_V4l2_EVENTS 100
|
||||
static DEFINE_MUTEX(bandwidth_mgr_mutex);
|
||||
|
@ -1784,9 +1787,10 @@ static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev,
|
|||
vfe_dev->error_info.error_count++;
|
||||
}
|
||||
|
||||
static int msm_isp_process_overflow_irq(
|
||||
int msm_isp_process_overflow_irq(
|
||||
struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1)
|
||||
uint32_t *irq_status0, uint32_t *irq_status1,
|
||||
uint8_t force_overflow)
|
||||
{
|
||||
uint32_t overflow_mask;
|
||||
uint32_t bus_err = 0;
|
||||
|
@ -1816,7 +1820,7 @@ static int msm_isp_process_overflow_irq(
|
|||
get_overflow_mask(&overflow_mask);
|
||||
overflow_mask &= *irq_status1;
|
||||
|
||||
if (overflow_mask) {
|
||||
if (overflow_mask || force_overflow) {
|
||||
struct msm_isp_event_data error_event;
|
||||
int i;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
|
@ -1840,7 +1844,8 @@ static int msm_isp_process_overflow_irq(
|
|||
pr_err("%s: wm %d assigned to stream handle %x\n",
|
||||
__func__, i, axi_data->free_wm[i]);
|
||||
}
|
||||
|
||||
vfe_dev->recovery_irq0_mask = vfe_dev->irq0_mask;
|
||||
vfe_dev->recovery_irq1_mask = vfe_dev->irq1_mask;
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
set_halt_restart_mask(vfe_dev);
|
||||
/* mask off other vfe if dual vfe is used */
|
||||
|
@ -1855,6 +1860,8 @@ static int msm_isp_process_overflow_irq(
|
|||
|
||||
atomic_set(&temp_vfe->error_info.overflow_state,
|
||||
OVERFLOW_DETECTED);
|
||||
temp_vfe->recovery_irq0_mask = temp_vfe->irq0_mask;
|
||||
temp_vfe->recovery_irq1_mask = temp_vfe->irq1_mask;
|
||||
temp_vfe->hw_info->vfe_ops.core_ops.
|
||||
set_halt_restart_mask(temp_vfe);
|
||||
}
|
||||
|
@ -1889,6 +1896,77 @@ void msm_isp_reset_burst_count_and_frame_drop(
|
|||
msm_isp_reset_framedrop(vfe_dev, stream_info);
|
||||
}
|
||||
|
||||
void msm_isp_prepare_irq_debug_info(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
struct msm_vfe_irq_debug_info *irq_debug;
|
||||
uint8_t current_index;
|
||||
|
||||
spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_irq_dump_lock, flags);
|
||||
/* Fill current VFE debug info */
|
||||
current_index = vfe_dev->common_data->vfe_irq_dump.
|
||||
current_irq_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE;
|
||||
irq_debug = &vfe_dev->common_data->vfe_irq_dump.
|
||||
irq_debug[current_index];
|
||||
irq_debug->vfe_id = vfe_dev->pdev->id;
|
||||
irq_debug->core_id = smp_processor_id();
|
||||
msm_isp_get_timestamp(&irq_debug->ts, vfe_dev);
|
||||
irq_debug->irq_status0[vfe_dev->pdev->id] = irq_status0;
|
||||
irq_debug->irq_status1[vfe_dev->pdev->id] = irq_status1;
|
||||
irq_debug->ping_pong_status[vfe_dev->pdev->id] =
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
get_pingpong_status(vfe_dev);
|
||||
if (vfe_dev->is_split &&
|
||||
(vfe_dev->common_data->
|
||||
dual_vfe_res->vfe_dev[!vfe_dev->pdev->id])
|
||||
&& (vfe_dev->common_data->dual_vfe_res->
|
||||
vfe_dev[!vfe_dev->pdev->id]->vfe_open_cnt)) {
|
||||
/* Fill other VFE debug Info */
|
||||
vfe_dev->hw_info->vfe_ops.irq_ops.read_irq_status(
|
||||
vfe_dev->common_data->dual_vfe_res->
|
||||
vfe_dev[!vfe_dev->pdev->id],
|
||||
&irq_debug->irq_status0[!vfe_dev->pdev->id],
|
||||
&irq_debug->irq_status1[!vfe_dev->pdev->id]);
|
||||
irq_debug->ping_pong_status[!vfe_dev->pdev->id] =
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
get_pingpong_status(vfe_dev->common_data->
|
||||
dual_vfe_res->vfe_dev[!vfe_dev->pdev->id]);
|
||||
}
|
||||
vfe_dev->common_data->vfe_irq_dump.current_irq_index++;
|
||||
spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_irq_dump_lock, flags);
|
||||
}
|
||||
|
||||
void msm_isp_prepare_tasklet_debug_info(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct msm_isp_timestamp ts)
|
||||
{
|
||||
struct msm_vfe_irq_debug_info *irq_debug;
|
||||
uint8_t current_index;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_tasklet_dump_lock, flags);
|
||||
current_index = vfe_dev->common_data->vfe_irq_dump.
|
||||
current_tasklet_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE;
|
||||
irq_debug = &vfe_dev->common_data->vfe_irq_dump.
|
||||
tasklet_debug[current_index];
|
||||
irq_debug->vfe_id = vfe_dev->pdev->id;
|
||||
irq_debug->core_id = smp_processor_id();
|
||||
irq_debug->ts = ts;
|
||||
irq_debug->irq_status0[vfe_dev->pdev->id] = irq_status0;
|
||||
irq_debug->irq_status1[vfe_dev->pdev->id] = irq_status1;
|
||||
irq_debug->ping_pong_status[vfe_dev->pdev->id] =
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
get_pingpong_status(vfe_dev);
|
||||
vfe_dev->common_data->vfe_irq_dump.current_tasklet_index++;
|
||||
spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_tasklet_dump_lock, flags);
|
||||
}
|
||||
|
||||
static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
|
@ -1923,7 +2001,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
|
|||
uint32_t error_mask0, error_mask1;
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.irq_ops.
|
||||
read_irq_status(vfe_dev, &irq_status0, &irq_status1);
|
||||
read_and_clear_irq_status(vfe_dev, &irq_status0, &irq_status1);
|
||||
|
||||
if ((irq_status0 == 0) && (irq_status1 == 0)) {
|
||||
ISP_DBG("%s:VFE%d irq_status0 & 1 are both 0\n",
|
||||
|
@ -1932,7 +2010,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
|
|||
}
|
||||
|
||||
if (msm_isp_process_overflow_irq(vfe_dev,
|
||||
&irq_status0, &irq_status1)) {
|
||||
&irq_status0, &irq_status1, 0)) {
|
||||
/* if overflow initiated no need to handle the interrupts */
|
||||
pr_err("overflow processed\n");
|
||||
return IRQ_HANDLED;
|
||||
|
@ -1953,7 +2031,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
|
|||
ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
msm_isp_prepare_irq_debug_info(vfe_dev, irq_status0, irq_status1);
|
||||
msm_isp_enqueue_tasklet_cmd(vfe_dev, irq_status0, irq_status1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -1991,6 +2069,8 @@ void msm_isp_do_tasklet(unsigned long data)
|
|||
irq_status1 = queue_cmd->vfeInterruptStatus1;
|
||||
ts = queue_cmd->ts;
|
||||
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
|
||||
msm_isp_prepare_tasklet_debug_info(vfe_dev,
|
||||
irq_status0, irq_status1, ts);
|
||||
ISP_DBG("%s: vfe_id %d status0: 0x%x status1: 0x%x\n",
|
||||
__func__, vfe_dev->pdev->id, irq_status0, irq_status1);
|
||||
irq_ops->process_reset_irq(vfe_dev,
|
||||
|
@ -2242,3 +2322,53 @@ void msm_isp_flush_tasklet(struct vfe_device *vfe_dev)
|
|||
return;
|
||||
}
|
||||
|
||||
void msm_isp_irq_debug_dump(struct vfe_device *vfe_dev)
|
||||
{
|
||||
|
||||
uint8_t i, dump_index;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_irq_dump_lock, flags);
|
||||
dump_index = vfe_dev->common_data->vfe_irq_dump.
|
||||
current_irq_index;
|
||||
for (i = 0; i < MAX_VFE_IRQ_DEBUG_DUMP_SIZE; i++) {
|
||||
trace_msm_cam_ping_pong_debug_dump(
|
||||
vfe_dev->common_data->vfe_irq_dump.
|
||||
irq_debug[dump_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE]);
|
||||
dump_index++;
|
||||
}
|
||||
spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_irq_dump_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
void msm_isp_tasklet_debug_dump(struct vfe_device *vfe_dev)
|
||||
{
|
||||
|
||||
uint8_t i, dump_index;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_tasklet_dump_lock, flags);
|
||||
dump_index = vfe_dev->common_data->vfe_irq_dump.
|
||||
current_tasklet_index;
|
||||
for (i = 0; i < MAX_VFE_IRQ_DEBUG_DUMP_SIZE; i++) {
|
||||
trace_msm_cam_tasklet_debug_dump(
|
||||
vfe_dev->common_data->vfe_irq_dump.
|
||||
tasklet_debug[
|
||||
dump_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE]);
|
||||
dump_index++;
|
||||
}
|
||||
spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
|
||||
common_dev_tasklet_dump_lock, flags);
|
||||
}
|
||||
|
||||
void msm_isp_dump_ping_pong_mismatch(struct vfe_device *vfe_dev)
|
||||
{
|
||||
|
||||
trace_msm_cam_string(" ***** msm_isp_dump_irq_debug ****");
|
||||
msm_isp_irq_debug_dump(vfe_dev);
|
||||
trace_msm_cam_string(" ***** msm_isp_dump_taskelet_debug ****");
|
||||
msm_isp_tasklet_debug_dump(vfe_dev);
|
||||
}
|
||||
|
|
|
@ -72,4 +72,9 @@ void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format);
|
|||
void msm_isp_flush_tasklet(struct vfe_device *vfe_dev);
|
||||
void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
|
||||
struct vfe_device *vfe_dev);
|
||||
void msm_isp_dump_ping_pong_mismatch(struct vfe_device *vfe_dev);
|
||||
int msm_isp_process_overflow_irq(
|
||||
struct vfe_device *vfe_dev,
|
||||
uint32_t *irq_status0, uint32_t *irq_status1,
|
||||
uint8_t force_overflow);
|
||||
#endif /* __MSM_ISP_UTIL_H__ */
|
||||
|
|
136
include/trace/events/msm_cam.h
Normal file
136
include/trace/events/msm_cam.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM msm_cam
|
||||
|
||||
#if !defined(_TRACE_MSM_VFE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_MSM_VFE_H
|
||||
|
||||
#include "msm_isp.h"
|
||||
#include <linux/types.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#define STRING_LEN 80
|
||||
|
||||
|
||||
TRACE_EVENT(msm_cam_string,
|
||||
TP_PROTO(const char *str),
|
||||
TP_ARGS(str),
|
||||
TP_STRUCT__entry(
|
||||
__array(char, str, STRING_LEN)
|
||||
),
|
||||
TP_fast_assign(
|
||||
strlcpy(__entry->str, str, STRING_LEN);
|
||||
),
|
||||
TP_printk("msm_cam: %s", __entry->str)
|
||||
);
|
||||
|
||||
TRACE_EVENT(msm_cam_tasklet_debug_dump,
|
||||
TP_PROTO(struct msm_vfe_irq_debug_info tasklet_state),
|
||||
TP_ARGS(tasklet_state),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, vfe_id)
|
||||
__field(unsigned int, core_id)
|
||||
__field(unsigned int, irq_status0)
|
||||
__field(unsigned int, irq_status1)
|
||||
__field(unsigned int, ping_pong_status)
|
||||
__field(long, tv_sec)
|
||||
__field(long, tv_usec)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->vfe_id = tasklet_state.vfe_id;
|
||||
__entry->irq_status0 =
|
||||
tasklet_state.irq_status0[tasklet_state.vfe_id];
|
||||
__entry->irq_status1 =
|
||||
tasklet_state.irq_status1[tasklet_state.vfe_id];
|
||||
__entry->core_id = tasklet_state.core_id;
|
||||
__entry->ping_pong_status =
|
||||
tasklet_state.ping_pong_status[tasklet_state.vfe_id];
|
||||
__entry->tv_sec =
|
||||
tasklet_state.ts.buf_time.tv_sec;
|
||||
__entry->tv_usec =
|
||||
tasklet_state.ts.buf_time.tv_usec;
|
||||
),
|
||||
TP_printk("vfe_id %d, core %d, irq_st0 0x%x, irq_st1 0x%x\n"
|
||||
"pi_po_st 0x%x, time %ld:%ld",
|
||||
__entry->vfe_id,
|
||||
__entry->core_id,
|
||||
__entry->irq_status0,
|
||||
__entry->irq_status1,
|
||||
__entry->ping_pong_status,
|
||||
__entry->tv_sec,
|
||||
__entry->tv_usec
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(msm_cam_ping_pong_debug_dump,
|
||||
TP_PROTO(struct msm_vfe_irq_debug_info ping_pong_state),
|
||||
TP_ARGS(ping_pong_state),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, curr_vfe_id)
|
||||
__field(unsigned int, curr_irq_status0)
|
||||
__field(unsigned int, curr_irq_status1)
|
||||
__field(unsigned int, curr_ping_pong_status)
|
||||
__field(unsigned int, othr_vfe_id)
|
||||
__field(unsigned int, othr_irq_status0)
|
||||
__field(unsigned int, othr_irq_status1)
|
||||
__field(unsigned int, othr_ping_pong_status)
|
||||
__field(long, othr_tv_sec)
|
||||
__field(long, othr_tv_usec)
|
||||
__field(unsigned int, core_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->curr_vfe_id =
|
||||
ping_pong_state.vfe_id;
|
||||
__entry->curr_irq_status0 =
|
||||
ping_pong_state.irq_status0[ping_pong_state.vfe_id];
|
||||
__entry->curr_irq_status1 =
|
||||
ping_pong_state.irq_status1[ping_pong_state.vfe_id];
|
||||
__entry->curr_ping_pong_status =
|
||||
ping_pong_state.
|
||||
ping_pong_status[ping_pong_state.vfe_id];
|
||||
__entry->othr_vfe_id =
|
||||
!ping_pong_state.vfe_id;
|
||||
__entry->othr_irq_status0 =
|
||||
ping_pong_state.irq_status0[!ping_pong_state.vfe_id];
|
||||
__entry->othr_irq_status1 =
|
||||
ping_pong_state.irq_status1[!ping_pong_state.vfe_id];
|
||||
__entry->othr_ping_pong_status =
|
||||
ping_pong_state.
|
||||
ping_pong_status[!ping_pong_state.vfe_id];
|
||||
__entry->othr_tv_sec =
|
||||
ping_pong_state.ts.buf_time.tv_sec;
|
||||
__entry->othr_tv_usec =
|
||||
ping_pong_state.ts.buf_time.tv_usec;
|
||||
__entry->core_id = ping_pong_state.core_id;
|
||||
),
|
||||
TP_printk("vfe_id %d, irq_st0 0x%x, irq_st1 0x%x, pi_po_st 0x%x\n"
|
||||
"other vfe_id %d, irq_st0 0x%x, irq_st1 0x%x\n"
|
||||
"pi_po_st 0x%x, time %ld:%ld core %d",
|
||||
__entry->curr_vfe_id,
|
||||
__entry->curr_irq_status0,
|
||||
__entry->curr_irq_status1,
|
||||
__entry->curr_ping_pong_status,
|
||||
__entry->othr_vfe_id,
|
||||
__entry->othr_irq_status0,
|
||||
__entry->othr_irq_status1,
|
||||
__entry->othr_ping_pong_status,
|
||||
__entry->othr_tv_sec,
|
||||
__entry->othr_tv_usec,
|
||||
__entry->core_id
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _MSM_CAM_TRACE_H */
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
Loading…
Add table
Reference in a new issue