summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h30
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp32.c11
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c14
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp44.c15
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp46.c14
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c17
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp48.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c20
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c144
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h5
-rw-r--r--include/trace/events/msm_cam.h136
14 files changed, 395 insertions, 21 deletions
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 35daf30bac63..840d84388a17 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -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++)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 9c7eba21fde1..4b881f4fd7b6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -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 {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 43f562b18209..bf18fc59585c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index ab01d37790d6..8e549c338bdd 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
index 0a72a041de28..957cbc292be3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
index f2d53c956fdc..cc768db875db 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 13c6e000fefc..ea4a595b1e00 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
index 55cf6a17b18c..22a1a21bce9a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
index f346ceb6c9e5..916f30049bf0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
@@ -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,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 941119fad78e..60801ff6be0a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -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;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 38ce78d941c9..72703c9590ed 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -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;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 4abb6d1d91a8..e238f54a9100 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -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);
+}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index f4280581a730..d075bd1721ac 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -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__ */
diff --git a/include/trace/events/msm_cam.h b/include/trace/events/msm_cam.h
new file mode 100644
index 000000000000..b52845407ef0
--- /dev/null
+++ b/include/trace/events/msm_cam.h
@@ -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>