Merge "defconfig: msm9625: enable filter table for ebtables."
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4147b44..bf022ac 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -1170,10 +1170,10 @@
 		this_dbs_info->cur_policy = NULL;
 		if (!cpu)
 			input_unregister_handler(&dbs_input_handler);
-		mutex_unlock(&dbs_mutex);
 		if (!dbs_enable)
 			sysfs_remove_group(cpufreq_global_kobject,
 					   &dbs_attr_group);
+		mutex_unlock(&dbs_mutex);
 
 		break;
 
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 f6b97d4..d412435 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -184,6 +184,7 @@
 	struct msm_vfe_stats_hardware_info *stats_hw_info;
 	struct v4l2_subdev_internal_ops *subdev_internal_ops;
 	struct v4l2_subdev_ops *subdev_ops;
+	uint32_t dmi_reg_offset;
 };
 
 struct msm_vfe_axi_hardware_info {
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 a522bd6..750963c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -919,6 +919,7 @@
 			.get_pingpong_status = msm_vfe32_get_pingpong_status,
 		},
 	},
+	.dmi_reg_offset = 0x5A0,
 	.axi_hw_info = &msm_vfe32_axi_hw_info,
 	.subdev_ops = &msm_vfe32_subdev_ops,
 	.subdev_internal_ops = &msm_vfe32_internal_ops,
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 dba59d7..ed4aa7f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1302,6 +1302,7 @@
 			.get_pingpong_status = msm_vfe40_get_pingpong_status,
 		},
 	},
+	.dmi_reg_offset = 0x918,
 	.axi_hw_info = &msm_vfe40_axi_hw_info,
 	.stats_hw_info = &msm_vfe40_stats_hw_info,
 	.subdev_ops = &msm_vfe40_subdev_ops,
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 606ee89..ac3ce0a 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
@@ -35,6 +35,8 @@
 	stream_cfg_cmd->axi_stream_handle =
 		(++axi_data->stream_handle_cnt) << 8 | i;
 
+	memset(&axi_data->stream_info[i], 0,
+		   sizeof(struct msm_vfe_axi_stream));
 	axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id;
 	axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id;
 	axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert;
@@ -621,7 +623,6 @@
 	int i;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
-	int send_update_complete = 0;
 	for (i = 0; i < MAX_NUM_STREAM; i++) {
 		if (axi_data->stream_info[i].state == START_PENDING ||
 				axi_data->stream_info[i].state ==
@@ -631,9 +632,6 @@
 				&wm_reload_mask, &reg_update_mask);
 			if (axi_data->stream_info[i].state == STOP_PENDING)
 				axi_data->stream_info[i].state = STOPPING;
-		} else if (axi_data->stream_info[i].state == STOPPING) {
-			send_update_complete = 1;
-			axi_data->stream_info[i].state = INACTIVE;
 		}
 	}
 	/*Reload AXI*/
@@ -642,47 +640,31 @@
 	/*Reg update per src*/
 	vfe_dev->hw_info->vfe_ops.core_ops.
 		reg_update(vfe_dev, reg_update_mask);
-	if (send_update_complete) {
+	if (vfe_dev->axi_data.stream_update) {
 		ISP_DBG("%s: send update complete\n", __func__);
 		vfe_dev->axi_data.stream_update = 0;
 		complete(&vfe_dev->stream_config_complete);
 	}
 }
 
-int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
-	struct timeval *tv)
+static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info)
 {
-	int i, rc = -1;
-	struct msm_isp_buffer *buf = NULL;
-	struct msm_isp_event_data buf_event;
-	uint32_t pingpong_bit = 0;
-	uint32_t bufq_handle = stream_info->bufq_handle;
-	uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+	int i;
+	struct msm_isp_buffer *buf = stream_info->buf[1];
+	for (i = 0; i < stream_info->num_planes; i++)
+		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
+		vfe_dev, stream_info->wm[i],
+		VFE_PING_FLAG, buf->mapped_info[i].paddr);
+	stream_info->buf[0] = buf;
+}
 
+static void msm_isp_get_done_buf(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+	struct msm_isp_buffer **done_buf)
+{
+	uint32_t pingpong_bit = 0, i;
 	pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
-	rc = vfe_dev->buf_mgr->ops->get_buf(
-		vfe_dev->buf_mgr, bufq_handle, &buf);
-	if (rc < 0) {
-		if (stream_info->stream_type == BURST_STREAM &&
-				stream_info->num_burst_capture <= 1) {
-			rc = 0;
-			if (pingpong_bit)
-				buf = stream_info->buf[0];
-			else
-				buf = stream_info->buf[1];
-		} else {
-			vfe_dev->error_info.
-				stream_framedrop_count[stream_idx]++;
-			return rc;
-		}
-	}
-
-	if (buf->num_planes != stream_info->num_planes) {
-		pr_err("%s: Invalid buffer\n", __func__);
-		rc = -EINVAL;
-		goto buf_error;
-	}
 	for (i = 0; i < stream_info->num_planes; i++) {
 		if (pingpong_bit !=
 			(~(pingpong_status >> stream_info->wm[i]) & 0x1)) {
@@ -690,19 +672,58 @@
 				__func__, pingpong_status);
 		}
 	}
+	*done_buf = stream_info->buf[pingpong_bit];
+}
+
+static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status)
+{
+	int i, rc = -1;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t pingpong_bit = 0;
+	uint32_t bufq_handle = stream_info->bufq_handle;
+	uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+
+	rc = vfe_dev->buf_mgr->ops->get_buf(
+		vfe_dev->buf_mgr, bufq_handle, &buf);
+	if (rc < 0) {
+		vfe_dev->error_info.
+			stream_framedrop_count[stream_idx]++;
+		return rc;
+	}
+
+	if (buf->num_planes != stream_info->num_planes) {
+		pr_err("%s: Invalid buffer\n", __func__);
+		rc = -EINVAL;
+		goto buf_error;
+	}
+
 	for (i = 0; i < stream_info->num_planes; i++)
 		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
 		vfe_dev, stream_info->wm[i],
 		pingpong_status, buf->mapped_info[i].paddr);
 
-	if (stream_info->buf[pingpong_bit] && tv) {
+	pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
+	stream_info->buf[pingpong_bit] = buf;
+	return 0;
+buf_error:
+	vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+		buf->bufq_handle, buf->buf_idx);
+	return rc;
+}
+
+static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf,
+	struct timeval *tv)
+{
+	struct msm_isp_event_data buf_event;
+	uint32_t frame_id = vfe_dev->axi_data.
+		src_info[stream_info->stream_src].frame_id;
+	if (buf && tv) {
 		if (stream_info->buf_divert) {
 			vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
-				stream_info->buf[pingpong_bit]->bufq_handle,
-				stream_info->buf[pingpong_bit]->buf_idx,
-				tv, stream_info->frame_id);
-
-			buf_event.frame_id = stream_info->frame_id;
+				buf->bufq_handle, buf->buf_idx, tv, frame_id);
+			buf_event.frame_id = frame_id;
 			buf_event.timestamp = *tv;
 			buf_event.u.buf_done.session_id =
 				stream_info->session_id;
@@ -710,24 +731,14 @@
 				stream_info->stream_id;
 			buf_event.u.buf_done.handle =
 				stream_info->bufq_handle;
-			buf_event.u.buf_done.buf_idx =
-			stream_info->buf[pingpong_bit]->buf_idx;
+			buf_event.u.buf_done.buf_idx = buf->buf_idx;
 			msm_isp_send_event(
 				vfe_dev, ISP_EVENT_BUF_DIVERT, &buf_event);
 		} else {
 			vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
-				stream_info->buf[pingpong_bit]->bufq_handle,
-				stream_info->buf[pingpong_bit]->buf_idx,
-				tv, stream_info->frame_id);
+				buf->bufq_handle, buf->buf_idx, tv, frame_id);
 		}
 	}
-
-	stream_info->buf[pingpong_bit] = buf;
-	return 0;
-buf_error:
-	vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
-		buf->bufq_handle, buf->buf_idx);
-	return rc;
 }
 
 enum msm_isp_camif_update_state
@@ -855,7 +866,6 @@
 			&axi_data->stream_info[
 				(stream_cfg_cmd->stream_handle[i] & 0xFF)];
 
-
 		if (stream_info->stream_src == RDI)
 			src_state =
 				axi_data->src_info[
@@ -869,9 +879,23 @@
 		if (stream_cfg_cmd->cmd == START_STREAM) {
 			/*Set address for both PING & PONG register */
 			rc = msm_isp_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PING_FLAG, NULL);
-			rc = msm_isp_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PONG_FLAG, NULL);
+				stream_info, VFE_PONG_FLAG);
+			if (rc < 0) {
+				pr_err("%s: No buffer for start stream\n",
+					   __func__);
+				return rc;
+			}
+			/* For burst stream of one capture, only one buffer
+			 * is allocated. Duplicate ping buffer address to pong
+			 * buffer to ensure hardware write to a valid address
+			 */
+			if (stream_info->stream_type == BURST_STREAM &&
+				stream_info->num_burst_capture <= 1) {
+				msm_isp_cfg_pong_address(vfe_dev, stream_info);
+			} else {
+				rc = msm_isp_cfg_ping_pong_address(vfe_dev,
+					stream_info, VFE_PING_FLAG);
+			}
 		}
 		if (src_state && camif_update != DISABLE_CAMIF) {
 			/*On the fly stream start/stop */
@@ -888,7 +912,8 @@
 	}
 	if (!wait_for_complete) {
 		/*Reload AXI*/
-		vfe_dev->hw_info->vfe_ops.axi_ops.
+		if (stream_cfg_cmd->cmd == START_STREAM)
+			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
 		/*Reg update per src*/
 		vfe_dev->hw_info->vfe_ops.core_ops.
@@ -904,7 +929,8 @@
 		axi_data->stream_update = 1;
 		spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
 		/*Reload AXI*/
-		vfe_dev->hw_info->vfe_ops.axi_ops.
+		if (stream_cfg_cmd->cmd == START_STREAM)
+			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
 		/*Reg update per src*/
 		vfe_dev->hw_info->vfe_ops.core_ops.
@@ -956,7 +982,8 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct timeval *tv)
 {
-	int i;
+	int i, rc = 0;
+	struct msm_isp_buffer *done_buf = NULL;
 	uint32_t comp_mask = 0, wm_mask = 0;
 	uint32_t pingpong_status, stream_idx;
 	struct msm_vfe_axi_stream *stream_info;
@@ -988,8 +1015,18 @@
 					__func__,
 					stream_idx, stream_info->frame_id);
 				stream_info->frame_id++;
-				msm_isp_cfg_ping_pong_address(vfe_dev,
-					stream_info, pingpong_status, tv);
+				msm_isp_get_done_buf(vfe_dev, stream_info,
+					pingpong_status, &done_buf);
+				if (stream_info->stream_type ==
+					CONTINUOUS_STREAM ||
+					stream_info->num_burst_capture > 1) {
+					rc = msm_isp_cfg_ping_pong_address(
+							vfe_dev, stream_info,
+							pingpong_status);
+				}
+				if (done_buf && !rc)
+					msm_isp_process_done_buf(vfe_dev,
+					stream_info, done_buf, tv);
 			}
 		}
 		wm_mask &= ~(comp_info->stream_composite_mask);
@@ -1005,8 +1042,16 @@
 			stream_idx = axi_data->free_wm[i] & 0xFF;
 			stream_info = &axi_data->stream_info[stream_idx];
 			stream_info->frame_id++;
-			msm_isp_cfg_ping_pong_address(vfe_dev,
-			stream_info, pingpong_status, tv);
+			msm_isp_get_done_buf(vfe_dev, stream_info,
+						pingpong_status, &done_buf);
+			if (stream_info->stream_type == CONTINUOUS_STREAM ||
+				stream_info->num_burst_capture > 1) {
+				rc = msm_isp_cfg_ping_pong_address(vfe_dev,
+					stream_info, pingpong_status);
+			}
+			if (done_buf && !rc)
+				msm_isp_process_done_buf(vfe_dev,
+				stream_info, done_buf, tv);
 		}
 	}
 	return;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 0c64c19..9765ae2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -52,10 +52,6 @@
 
 void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
 
-int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
-	struct timeval *tv);
-
 void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);
 void msm_isp_update_framedrop_count(struct vfe_device *vfe_dev);
 void msm_isp_sof_notify(struct vfe_device *vfe_dev,
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 ab8dc95..e181b53 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
@@ -219,15 +219,15 @@
 				lo_val1 = lo_val & 0x0000FFFF;
 				lo_val = (lo_val & 0xFFFF0000)>>16;
 				msm_camera_io_w(lo_val1, vfe_dev->vfe_base +
-								0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 			} else if (reg_cfg_cmd->cmd_type ==
 					VFE_WRITE_DMI_64BIT) {
 				hi_val = *hi_tbl_ptr++;
 				msm_camera_io_w(hi_val, vfe_dev->vfe_base +
-					   0x0918);
+					   vfe_dev->hw_info->dmi_reg_offset);
 			}
 			msm_camera_io_w(lo_val, vfe_dev->vfe_base +
-							0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 		}
 		break;
 	}
@@ -258,16 +258,16 @@
 		for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
 			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
 				hi_val = msm_camera_io_r(vfe_dev->vfe_base +
-								0x0918);
+					vfe_dev->hw_info->dmi_reg_offset);
 				*hi_tbl_ptr++ = hi_val;
 			}
 
 			lo_val = msm_camera_io_r(vfe_dev->vfe_base +
-							0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 
 			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) {
 				lo_val1 = msm_camera_io_r(vfe_dev->vfe_base +
-								0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 				lo_val |= lo_val1 << 16;
 			}
 			*lo_tbl_ptr++ = lo_val;