msm: camera: Add free status buffer queue

Add support for free buffer queues for vfe
statistics

Change-Id: I9a791d5869aa090f661904b41b210cea51f67aa4
Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 63120da..5703d88 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -11,7 +11,7 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   EXTRA_CFLAGS += -Idrivers/media/video/msm/server
-  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
   obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CPP) += cpp/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c3e8321..08278ff 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -131,6 +131,8 @@
 	uint32_t    id;
 	uint32_t    buffer;
 	uint32_t    frameCounter;
+	int32_t     buf_idx;
+	int32_t     fd;
 };
 
 struct msm_free_buf {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5c61cdb..5fcb62b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -406,12 +406,14 @@
 		struct msm_stats_buf stats;
 		struct isp_msg_stats *isp_stats = (struct isp_msg_stats *)arg;
 
+		memset(&stats, 0, sizeof(stats));
 		isp_event->isp_data.isp_msg.msg_id = isp_stats->id;
 		isp_event->isp_data.isp_msg.frame_id =
 			isp_stats->frameCounter;
-		stats.buffer = msm_pmem_stats_ptov_lookup(pmctl,
-						isp_stats->buffer,
-						&(stats.fd));
+		stats.buffer = isp_stats->buffer;
+		stats.fd = isp_stats->fd;
+		/* buf_idx used for O(0) lookup */
+		stats.buf_idx = isp_stats->buf_idx;
 		switch (isp_stats->id) {
 		case MSG_ID_STATS_AEC:
 			stats.aec.buff = stats.buffer;
@@ -453,8 +455,8 @@
 				kmalloc(sizeof(struct msm_stats_buf),
 							GFP_ATOMIC);
 			if (!stats_buf) {
-				pr_err("%s: out of memory.\n",
-							__func__);
+				pr_err("%s: out of memory. stats_id = %d\n",
+					__func__, isp_stats->id);
 				rc = -ENOMEM;
 			} else {
 				*stats_buf = stats;
@@ -550,7 +552,6 @@
 	struct msm_cam_media_controller *mctl, void __user *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
-	struct msm_pmem_region region[8];
 	struct axidata axi_data;
 
 	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
@@ -562,103 +563,13 @@
 	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
 	switch (cfgcmd.cmd_type) {
 	case CMD_STATS_AF_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AF, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AEC_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AEC, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AWB_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AWB, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AEC_AWB_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AEC_AWB, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_IHIST_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_IHIST, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_RS_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_RS, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_CS_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_CS, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
+		return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
 	case CMD_GENERAL:
 	case CMD_STATS_DISABLE:
 		return msm_isp_subdev_ioctl(sd, &cfgcmd,
@@ -764,6 +675,62 @@
 	return rc;
 }
 
+static int msm_vfe_stats_buf_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd,
+	struct msm_cam_media_controller *mctl,
+	void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	int rc = 0;
+	switch (cmd) {
+	case MSM_CAM_IOCTL_STATS_REQBUF: {
+		struct msm_stats_reqbuf reqbuf;
+		if (copy_from_user(&reqbuf, arg,
+			sizeof(struct msm_stats_reqbuf))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_REQBUF;
+	cfgcmd.value = (void *)&reqbuf;
+	cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+	break;
+	}
+	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
+		struct msm_stats_buf_info buf_info;
+
+		if (copy_from_user(&buf_info, arg,
+			sizeof(struct msm_stats_buf_info))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_ENQUEUEBUF;
+	cfgcmd.value = (void *)&buf_info;
+	cfgcmd.length = sizeof(struct msm_stats_buf_info);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+	break;
+	}
+	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq bufq_info;
+
+		if (copy_from_user(&bufq_info, arg,
+			sizeof(struct msm_stats_flush_bufq))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+	}
+	cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
+	cfgcmd.value = (void *)&bufq_info;
+	cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+	break;
+	}
+	default:
+		rc = -1;
+	break;
+	}
+	CDBG("%s\n", __func__);
+	return rc;
+}
 /* config function simliar to origanl msm_ioctl_config*/
 static int msm_isp_config(struct msm_cam_media_controller *pmctl,
 			 unsigned int cmd, unsigned long arg)
@@ -789,6 +756,12 @@
 		rc = msm_put_stats_buffer(sd, pmctl, argp);
 		break;
 
+	case MSM_CAM_IOCTL_STATS_REQBUF:
+	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
+	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+		rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
+		break;
+
 	default:
 		break;
 	}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index fa985ce..2331fcc 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -365,6 +365,229 @@
 	"DEMOSAICV3_UPDATE",
 };
 
+
+static unsigned long vfe31_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+	rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
+			stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	return buf->paddr;
+}
+
+static unsigned long vfe31_stats_flush_enqueue(
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+
+	rc = vfe31_ctrl->stats_ops.bufq_flush(
+			vfe31_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe31_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe31_ctrl->stats_ops.enqueue_buf(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf (type = %d) err = %d",
+				__func__, stats_type, rc);
+			return rc;
+		}
+	}
+	return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_af_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf err = %d",
+			__func__, rc);
+		spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+		return -EINVAL;
+	}
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+	return 0;
+}
+
 static void vfe31_stop(void)
 {
 	uint8_t  axiBusyFlag = true;
@@ -600,101 +823,6 @@
 	return 0;
 }
 
-static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
-	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
-	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
-
-	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
-
-	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
-	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
-	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
 static void msm_camera_io_dump2(void __iomem *addr, int size)
 {
 	char line_str[BUFF_SIZE_128], *p_str;
@@ -1388,6 +1516,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START:
+		rc = vfe_stats_aec_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AEC",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1408,6 +1542,12 @@
 		cmdp, (vfe31_cmd[cmd->id].length));
 		break;
 	case VFE_CMD_STATS_AF_START:
+		rc = vfe_stats_af_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AF",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1428,6 +1568,12 @@
 		cmdp, (vfe31_cmd[cmd->id].length));
 		break;
 	case VFE_CMD_STATS_AWB_START:
+		rc = vfe_stats_awb_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1449,6 +1595,12 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START:
+		rc = vfe_stats_ihist_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of IHIST",
+			__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1470,6 +1622,12 @@
 		break;
 
 	case VFE_CMD_STATS_RS_START:
+		rc = vfe_stats_rs_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of RS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1487,6 +1645,12 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START:
+		rc = vfe_stats_cs_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of CS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1987,6 +2151,12 @@
 		old_val &= ~AF_BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+		}
 		break;
 
 	case VFE_CMD_STATS_IHIST_STOP:
@@ -2172,76 +2342,6 @@
 	return rc;
 }
 
-static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->af_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->afStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->awb_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->awbStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->aec_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->aecStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->ihist_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->rs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->rsStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->cs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->csStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
 static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
 {
 	uint32_t *temp;
@@ -2810,7 +2910,8 @@
 static void
 vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
 {
-	unsigned long flags;
+	int rc = 0;
+	void *vaddr = NULL;
 	/* fill message with right content. */
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
@@ -2821,55 +2922,72 @@
 	switch (statsNum) {
 	case STATS_AE_NUM:{
 		msgStats.id = MSG_ID_STATS_AEC;
-		spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
-		vfe31_ctrl->aecStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AEC,	bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_AF_NUM:{
 		msgStats.id = MSG_ID_STATS_AF;
-		spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
-		vfe31_ctrl->afStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AF, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_AWB_NUM: {
 		msgStats.id = MSG_ID_STATS_AWB;
-		spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
-		vfe31_ctrl->awbStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AWB, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 
 	case STATS_IHIST_NUM: {
 		msgStats.id = MSG_ID_STATS_IHIST;
-		spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
-		vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_IHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_RS_NUM: {
 		msgStats.id = MSG_ID_STATS_RS;
-		spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
-		vfe31_ctrl->rsStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_RS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_CS_NUM: {
 		msgStats.id = MSG_ID_STATS_CS;
-		spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
-		vfe31_ctrl->csStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_CS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 
 	default:
 		goto stats_done;
 	}
-
-	v4l2_subdev_notify(&vfe31_ctrl->subdev,
-				NOTIFY_VFE_MSG_STATS,
-				&msgStats);
+	if (rc == 0) {
+		msgStats.buffer = (uint32_t)vaddr;
+		v4l2_subdev_notify(&vfe31_ctrl->subdev,
+			NOTIFY_VFE_MSG_STATS, &msgStats);
+	} else {
+		pr_err("%s: paddr to idx mapping error, stats_id = %d,\n"
+			"paddr = 0x%d\n", __func__,
+			 msgStats.id, msgStats.buffer);
+	}
 stats_done:
 	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
@@ -2901,17 +3019,18 @@
 static void vfe31_process_stats_ae_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
-	if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->aecStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AE_NUM,
-			vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
 			STATS_AE_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
 		vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -2921,17 +3040,18 @@
 static void vfe31_process_stats_awb_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
-	if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->awbStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AWB_NUM,
-			vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
 			STATS_AWB_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
 		vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -2941,17 +3061,18 @@
 static void vfe31_process_stats_af_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
-	if (!(vfe31_ctrl->afStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->afStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AF_NUM,
-			vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
 			STATS_AF_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
 		vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -2960,27 +3081,35 @@
 
 static void vfe31_process_stats_ihist_irq(void)
 {
-	if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->ihistStatsControl.bufToRender =
-			vfe31_process_stats_irq_common(STATS_IHIST_NUM,
-			vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
-
+			  vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+				addr);
 		vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
-			STATS_IHIST_NUM);
+			  STATS_IHIST_NUM);
 	} else {
 		vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+			 vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
 	}
 }
 
 static void vfe31_process_stats_rs_irq(void)
 {
-	if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->rsStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_RS_NUM,
-			vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
-
+			addr);
 		vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
 			STATS_RS_NUM);
 	} else {
@@ -2992,12 +3121,29 @@
 
 static void vfe31_process_stats_cs_irq(void)
 {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe31_ctrl->csStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(STATS_CS_NUM,
+				addr);
+			vfe_send_stats_msg(
+				vfe31_ctrl->csStatsControl.bufToRender,
+				STATS_CS_NUM);
+	} else {
+		vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+	}
 	if (!(vfe31_ctrl->csStatsControl.ackPending)) {
 		vfe31_ctrl->csStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_CS_NUM,
-			vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
-
-		vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+				vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+		vfe_send_stats_msg(
+			vfe31_ctrl->csStatsControl.bufToRender,
 			STATS_CS_NUM);
 	} else {
 		vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3010,15 +3156,16 @@
 {
 	unsigned long flags;
 	int32_t process_stats = false;
+	uint32_t addr;
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 
-	spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
-		if (!vfe31_ctrl->aecStatsControl.ackPending) {
-			vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+		if (addr) {
 			vfe31_ctrl->aecStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AE_NUM,
-				vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe31_ctrl->aecStatsControl.bufToRender = 0;
@@ -3029,11 +3176,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
-		if (!vfe31_ctrl->awbStatsControl.ackPending) {
-			vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+		if (addr) {
 			vfe31_ctrl->awbStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AWB_NUM,
-				vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3045,11 +3192,11 @@
 
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
-		if (!vfe31_ctrl->afStatsControl.ackPending) {
-			vfe31_ctrl->afStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+		if (addr) {
 			vfe31_ctrl->afStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AF_NUM,
-				vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->afStatsControl.bufToRender = 0;
@@ -3060,11 +3207,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
-		if (!vfe31_ctrl->ihistStatsControl.ackPending) {
-			vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+		if (addr) {
 			vfe31_ctrl->ihistStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_IHIST_NUM,
-				vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3075,11 +3222,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
-		if (!vfe31_ctrl->rsStatsControl.ackPending) {
-			vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+		if (!addr) {
 			vfe31_ctrl->rsStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_RS_NUM,
-				vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3091,11 +3238,11 @@
 
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
-		if (!vfe31_ctrl->csStatsControl.ackPending) {
-			vfe31_ctrl->csStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+		if (addr) {
 			vfe31_ctrl->csStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_CS_NUM,
-				vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3105,13 +3252,91 @@
 		vfe31_ctrl->csStatsControl.bufToRender = 0;
 	}
 
-	spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
 	if (process_stats)
 		vfe_send_comp_stats_msg(status_bits);
 
 	return;
 }
 
+static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+	void *ion_client)
+{
+	long rc = 0;
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+		if (!vfe31_ctrl->stats_ops.stats_ctrl) {
+			/* stats_ctrl has not been init yet */
+			rc = msm_stats_buf_ops_init(&vfe31_ctrl->stats_ctrl,
+					(struct ion_client *)ion_client,
+					&vfe31_ctrl->stats_ops);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats ops", __func__);
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.stats_ctrl_init(
+				&vfe31_ctrl->stats_ctrl);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats_ctrl ops", __func__);
+			memset(&vfe31_ctrl->stats_ops, 0,
+				sizeof(vfe31_ctrl->stats_ops));
+			goto end;
+		}
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mis match\n",
+				 __func__, cmd->length,
+				 sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+	rc = vfe31_ctrl->stats_ops.reqbuf(&vfe31_ctrl->stats_ctrl,
+			(struct msm_stats_reqbuf *)cmd->value,
+			vfe31_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+		if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats enqueuebuf input size = %d,\n"
+				"struct size = %d, mis match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
+				(struct msm_stats_buf_info *)cmd->value,
+				vfe31_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.bufq_flush(&vfe31_ctrl->stats_ctrl,
+				(enum msm_stats_enum_type)flush_req->stats_type,
+				vfe31_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported", __func__,
+			cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static void vfe31_process_stats_irq(uint32_t *irqstatus)
 {
 	uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
@@ -3334,44 +3559,55 @@
 	void *data = vfe_params->data;
 
 	long rc = 0;
-	uint32_t i = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
-	struct msm_pmem_region   *regptr = NULL;
 	struct vfe_cmd_stats_ack *sack = NULL;
-	if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-		if (NULL != cmd->value) {
-			if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
-				pr_err("%s %d: copy_from_user failed\n",
-					__func__, __LINE__);
-				return -EFAULT;
-			}
-		}
-	} else {
-	/* here eith stats release or frame release. */
+
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+		return rc;
+	default:
+		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+				if (copy_from_user(&vfecmd,
+					(void __user *)(cmd->value),
+					sizeof(vfecmd))) {
+						pr_err("%s %d: copy_from_user failed\n",
+						__func__, __LINE__);
+					return -EFAULT;
+				}
+		} else {
+		/* here eith stats release or frame release. */
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
 			/* then must be stats release. */
-			if (!data)
+			if (!data) {
+				pr_err("%s: data = NULL, cmd->cmd_type = %d",
+					__func__, cmd->cmd_type);
 				return -EFAULT;
+			}
 			sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
 							GFP_ATOMIC);
-			if (!sack)
+			if (!sack) {
+				pr_err("%s: no mem for cmd->cmd_type = %d",
+					 __func__, cmd->cmd_type);
 				return -ENOMEM;
+			}
 
 			sack->nextStatsBuf = *(uint32_t *)data;
 		}
-	}
+	  }
 
 	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
 
@@ -3381,53 +3617,7 @@
 		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
-		struct axidata *axid;
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
-			goto vfe31_config_done;
-		}
-
-		scfg =
-			kmalloc(sizeof(struct vfe_cmd_stats_buf),
-				GFP_ATOMIC);
-		if (!scfg) {
-			rc = -ENOMEM;
-			goto vfe31_config_done;
-		}
-		regptr = axid->region;
-		if (axid->bufnum1 > 0) {
-			for (i = 0; i < axid->bufnum1; i++) {
-				scfg->statsBuf[i] =
-					(uint32_t)(regptr->paddr);
-				regptr++;
-			}
-		}
-		/* individual */
-		switch (cmd->cmd_type) {
-		case CMD_STATS_AEC_ENABLE:
-			rc = vfe_stats_aec_buf_init(scfg);
-			break;
-		case CMD_STATS_AF_ENABLE:
-			rc = vfe_stats_af_buf_init(scfg);
-			break;
-		case CMD_STATS_AWB_ENABLE:
-			rc = vfe_stats_awb_buf_init(scfg);
-			break;
-		case CMD_STATS_IHIST_ENABLE:
-			rc = vfe_stats_ihist_buf_init(scfg);
-			break;
-		case CMD_STATS_RS_ENABLE:
-			rc = vfe_stats_rs_buf_init(scfg);
-			break;
-		case CMD_STATS_CS_ENABLE:
-			rc = vfe_stats_cs_buf_init(scfg);
-			break;
-		default:
-			pr_err("%s Unsupported cmd type %d",
-				__func__, cmd->cmd_type);
-			break;
-		}
+		scfg = NULL;
 		goto vfe31_config_done;
 	}
 	switch (cmd->cmd_type) {
@@ -3459,36 +3649,6 @@
 	case CMD_SNAP_BUF_RELEASE:
 		break;
 
-	case CMD_STATS_AEC_BUF_RELEASE: {
-		vfe31_stats_aec_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_AF_BUF_RELEASE: {
-		vfe31_stats_af_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_AWB_BUF_RELEASE: {
-		vfe31_stats_awb_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_IHIST_BUF_RELEASE: {
-		vfe31_stats_ihist_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_RS_BUF_RELEASE: {
-		vfe31_stats_rs_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_CS_BUF_RELEASE: {
-		vfe31_stats_cs_ack(sack);
-		}
-		break;
-
 	case CMD_AXI_CFG_PRIM: {
 		uint32_t *axio = NULL;
 		axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -3607,6 +3767,7 @@
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cmd->cmd_type);
 		break;
+		}
 	}
 vfe31_config_done:
 	kfree(scfg);
@@ -3714,17 +3875,10 @@
 
 	spin_lock_init(&vfe31_ctrl->stop_flag_lock);
 	spin_lock_init(&vfe31_ctrl->state_lock);
+	spin_lock_init(&vfe31_ctrl->stats_bufq_lock);
 	spin_lock_init(&vfe31_ctrl->io_lock);
 	spin_lock_init(&vfe31_ctrl->update_ack_lock);
 	spin_lock_init(&vfe31_ctrl->tasklet_lock);
-
-	spin_lock_init(&vfe31_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe31_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe31_ctrl->af_ack_lock);
-	spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
-	spin_lock_init(&vfe31_ctrl->rs_ack_lock);
-	spin_lock_init(&vfe31_ctrl->cs_ack_lock);
-	spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
 	spin_lock_init(&vfe31_ctrl->sd_notify_lock);
 	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
 
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index 739d157..2cba995 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -15,6 +15,7 @@
 #define __MSM_VFE31_V4L2_H__
 
 #include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
 
 #ifndef TRUE
 #define TRUE 1
@@ -862,14 +863,7 @@
 	spinlock_t  update_ack_lock;
 	spinlock_t  state_lock;
 	spinlock_t  io_lock;
-
-	spinlock_t  aec_ack_lock;
-	spinlock_t  awb_ack_lock;
-	spinlock_t  af_ack_lock;
-	spinlock_t  ihist_ack_lock;
-	spinlock_t  rs_ack_lock;
-	spinlock_t  cs_ack_lock;
-	spinlock_t  comp_stats_ack_lock;
+	spinlock_t  stats_bufq_lock;
 
 	uint32_t extlen;
 	void *extdata;
@@ -930,6 +924,8 @@
 	uint32_t frame_skip_cnt;
 	uint32_t frame_skip_pattern;
 	uint32_t snapshot_frame_cnt;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
 };
 
 enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3ac4c6a..621a016 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -624,116 +624,248 @@
 	return 0;
 }
 
-static uint32_t vfe_stats_awb_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static unsigned long vfe32_stats_dqbuf(struct vfe32_ctrl_type *vfe32_ctrl,
+	enum msm_stats_enum_type stats_type)
 {
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+	rc = vfe32_ctrl->stats_ops.dqbuf(
+			vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	return buf->paddr;
+}
 
-	addr = ptr[0];
+static unsigned long vfe32_stats_flush_enqueue(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+
+	rc = vfe32_ctrl->stats_ops.bufq_flush(
+			vfe32_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe32_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe32_ctrl->stats_ops.enqueue_buf(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf (type = %d) err = %d",
+				 __func__, stats_type, rc);
+			return rc;
+		}
+	}
+	return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AWB_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AWB_WR_PONG_ADDR);
-	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_aec_buf_init(
+static int vfe_stats_aec_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AEC_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
-	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_af_buf_init(
+static int vfe_stats_af_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
+	int rc = 0;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf err = %d",
+			   __func__, rc);
+		spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+		return -EINVAL;
+	}
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AF_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AF_WR_PONG_ADDR);
 
-	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_ihist_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_ihist_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_HIST_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_HIST_WR_PONG_ADDR);
 
-	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_rs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_rs_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_RS_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
-	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_cs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_cs_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
-
-	addr = ptr[0];
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_CS_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
-	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
@@ -1614,6 +1746,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START: {
+		rc = vfe_stats_aec_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AEC",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1637,6 +1775,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_START: {
+		rc = vfe_stats_af_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AF",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1660,6 +1804,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AWB_START: {
+		rc = vfe_stats_awb_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1684,6 +1834,12 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START: {
+		rc = vfe_stats_ihist_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of IHIST",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1709,6 +1865,12 @@
 
 
 	case VFE_CMD_STATS_RS_START: {
+		rc = vfe_stats_rs_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of RS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1728,6 +1890,12 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START: {
+		rc = vfe_stats_cs_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of CS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -2430,6 +2598,12 @@
 		old_val &= ~AF_BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+		}
 		}
 		break;
 
@@ -2808,82 +2982,6 @@
 	return rc;
 }
 
-static void vfe32_stats_af_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->af_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->afStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_awb_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->awb_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->awbStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_aec_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->aec_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->aecStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_ihist_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->ihist_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_rs_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->rs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->rsStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_cs_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->cs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->csStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
 static inline void vfe32_read_irq_status(
 	struct axi_ctrl_t *axi_ctrl, struct vfe32_irq_status *out)
 {
@@ -3653,70 +3751,87 @@
 	return returnAddr;
 }
 
-static void
-vfe_send_stats_msg(struct vfe32_ctrl_type *vfe32_ctrl,
+static void vfe_send_stats_msg(
+	struct vfe32_ctrl_type *vfe32_ctrl,
 	uint32_t bufAddress, uint32_t statsNum)
 {
-	unsigned long flags;
+	int rc = 0;
+	void *vaddr = NULL;
 	/* fill message with right content. */
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
 	struct isp_msg_stats msgStats;
 	msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
 	msgStats.buffer = bufAddress;
-
 	switch (statsNum) {
 	case statsAeNum:{
 		msgStats.id = MSG_ID_STATS_AEC;
-		spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
-		vfe32_ctrl->aecStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AEC, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAfNum:{
 		msgStats.id = MSG_ID_STATS_AF;
-		spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
-		vfe32_ctrl->afStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AF, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAwbNum: {
 		msgStats.id = MSG_ID_STATS_AWB;
-		spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
-		vfe32_ctrl->awbStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AWB, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 
 	case statsIhistNum: {
 		msgStats.id = MSG_ID_STATS_IHIST;
-		spin_lock_irqsave(&vfe32_ctrl->ihist_ack_lock, flags);
-		vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->ihist_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_IHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsRsNum: {
 		msgStats.id = MSG_ID_STATS_RS;
-		spin_lock_irqsave(&vfe32_ctrl->rs_ack_lock, flags);
-		vfe32_ctrl->rsStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->rs_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_RS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsCsNum: {
 		msgStats.id = MSG_ID_STATS_CS;
-		spin_lock_irqsave(&vfe32_ctrl->cs_ack_lock, flags);
-		vfe32_ctrl->csStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->cs_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_CS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 
 	default:
 		goto stats_done;
 	}
-
-	v4l2_subdev_notify(&vfe32_ctrl->subdev,
-				NOTIFY_VFE_MSG_STATS,
-				&msgStats);
+	if (rc == 0) {
+		msgStats.buffer = (uint32_t)vaddr;
+		v4l2_subdev_notify(&vfe32_ctrl->subdev,
+			NOTIFY_VFE_MSG_STATS,
+			&msgStats);
+	} else {
+		pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+			 __func__, msgStats.id, msgStats.buffer);
+	}
 stats_done:
 	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
@@ -3751,17 +3866,18 @@
 static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
-	if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->aecStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
-			vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
 		vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -3771,17 +3887,18 @@
 static void vfe32_process_stats_awb_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
-	if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->awbStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAwbNum,
-			vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->awbStatsControl.bufToRender, statsAwbNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
 		vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -3791,17 +3908,18 @@
 static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
-	if (!(vfe32_ctrl->afStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->afStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
-			vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
 		vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -3810,11 +3928,15 @@
 
 static void vfe32_process_stats_ihist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->ihistStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(
-			vfe32_ctrl, statsIhistNum,
-			vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+			vfe32_ctrl, statsIhistNum, addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->ihistStatsControl.bufToRender,
@@ -3828,10 +3950,15 @@
 
 static void vfe32_process_stats_rs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->rsStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsRsNum,
-			vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->rsStatsControl.bufToRender, statsRsNum);
@@ -3844,13 +3971,19 @@
 
 static void vfe32_process_stats_cs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->csStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->csStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsCsNum,
-			vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+			addr);
 
-		vfe_send_stats_msg(vfe32_ctrl,
-			vfe32_ctrl->csStatsControl.bufToRender, statsCsNum);
+			vfe_send_stats_msg(vfe32_ctrl,
+				vfe32_ctrl->csStatsControl.bufToRender,
+				statsCsNum);
 	} else {
 		vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3863,16 +3996,17 @@
 {
 	unsigned long flags;
 	int32_t process_stats = false;
-	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+	uint32_t addr;
 
-	spin_lock_irqsave(&vfe32_ctrl->comp_stats_ack_lock, flags);
+	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
-		if (!vfe32_ctrl->aecStatsControl.ackPending) {
-			vfe32_ctrl->aecStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+				MSM_STATS_TYPE_AEC);
+		if (addr) {
 			vfe32_ctrl->aecStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
-				vfe32_ctrl, statsAeNum,
-				vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+				vfe32_ctrl, statsAeNum,	addr);
 			process_stats = true;
 		} else{
 			vfe32_ctrl->aecStatsControl.bufToRender = 0;
@@ -3883,12 +4017,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
-		if (!vfe32_ctrl->awbStatsControl.ackPending) {
-			vfe32_ctrl->awbStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+			MSM_STATS_TYPE_AWB);
+		if (addr) {
 			vfe32_ctrl->awbStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAwbNum,
-				vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3898,14 +4033,14 @@
 		vfe32_ctrl->awbStatsControl.bufToRender = 0;
 	}
 
-
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
-		if (!vfe32_ctrl->afStatsControl.ackPending) {
-			vfe32_ctrl->afStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_AF);
+		if (addr) {
 			vfe32_ctrl->afStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAfNum,
-				vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->afStatsControl.bufToRender = 0;
@@ -3916,12 +4051,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
-		if (!vfe32_ctrl->ihistStatsControl.ackPending) {
-			vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_IHIST);
+		if (addr) {
 			vfe32_ctrl->ihistStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsIhistNum,
-				vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3932,12 +4068,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
-		if (!vfe32_ctrl->rsStatsControl.ackPending) {
-			vfe32_ctrl->rsStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_RS);
+		if (addr) {
 			vfe32_ctrl->rsStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsRsNum,
-				vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3948,12 +4085,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
-		if (!vfe32_ctrl->csStatsControl.ackPending) {
-			vfe32_ctrl->csStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_CS);
+		if (addr) {
 			vfe32_ctrl->csStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsCsNum,
-				vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3962,8 +4100,7 @@
 	} else {
 		vfe32_ctrl->csStatsControl.bufToRender = 0;
 	}
-
-	spin_unlock_irqrestore(&vfe32_ctrl->comp_stats_ack_lock, flags);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (process_stats)
 		vfe_send_comp_stats_msg(vfe32_ctrl, status_bits);
 
@@ -4259,6 +4396,88 @@
 	return 0;
 }
 
+static long vfe_stats_bufq_sub_ioctl(
+	struct vfe32_ctrl_type *vfe_ctrl,
+	struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+	long rc = 0;
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	if (!vfe_ctrl->stats_ops.stats_ctrl) {
+		/* stats_ctrl has not been init yet */
+		rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+				(struct ion_client *)ion_client,
+				&vfe_ctrl->stats_ops);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats ops", __func__);
+			goto end;
+		}
+		rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats_ctrl ops", __func__);
+			memset(&vfe_ctrl->stats_ops, 0,
+				sizeof(vfe_ctrl->stats_ops));
+			goto end;
+		}
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+	}
+	rc = vfe_ctrl->stats_ops.reqbuf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_reqbuf *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+		/* error. the length not match */
+		pr_err("%s: stats enqueuebuf input size = %d,\n"
+			"struct size = %d, mitch match\n",
+			 __func__, cmd->length,
+			sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.enqueue_buf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_buf_info *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+	{
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.bufq_flush(
+			&vfe_ctrl->stats_ctrl,
+			(enum msm_stats_enum_type)flush_req->stats_type,
+			vfe_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported", __func__,
+			cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
@@ -4273,9 +4492,7 @@
 	void *data = vfe_params->data;
 
 	long rc = 0;
-	uint32_t i = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
-	struct msm_pmem_region   *regptr = NULL;
 	struct vfe_cmd_stats_ack *sack = NULL;
 
 	if (!vfe32_ctrl->share_ctrl->vfebase) {
@@ -4283,151 +4500,100 @@
 		return -EFAULT;
 	}
 
-	if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
+	switch (cmd->cmd_type) {
+	case CMD_VFE_PROCESS_IRQ:
 		vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
 		return rc;
-	} else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-		if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
-			pr_err("%s %d: copy_from_user failed\n", __func__,
-				__LINE__);
-			return -EFAULT;
-		}
-	} else {
-	/* here eith stats release or frame release. */
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
+				cmd, vfe_params->data);
+		return rc;
+	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
-			/* then must be stats release. */
-			if (!data)
-				return -EFAULT;
-			sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+				if (copy_from_user(&vfecmd,
+					(void __user *)(cmd->value),
+					sizeof(vfecmd))) {
+						pr_err("%s %d: copy_from_user failed\n",
+							__func__, __LINE__);
+					return -EFAULT;
+				}
+		} else {
+			/* here eith stats release or frame release. */
+			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+				/* then must be stats release. */
+				if (!data) {
+					pr_err("%s: data = NULL, cmd->cmd_type = %d",
+						__func__, cmd->cmd_type);
+					return -EFAULT;
+				}
+				sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
 							GFP_ATOMIC);
-			if (!sack)
-				return -ENOMEM;
-
-			sack->nextStatsBuf = *(uint32_t *)data;
-		}
-	}
-
-	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
-
-	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
-		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
-		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
-		struct axidata *axid;
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
-			goto vfe32_config_done;
-		}
-
-		scfg =
-			kmalloc(sizeof(struct vfe_cmd_stats_buf),
-				GFP_ATOMIC);
-		if (!scfg) {
-			rc = -ENOMEM;
-			goto vfe32_config_done;
-		}
-		regptr = axid->region;
-		if (axid->bufnum1 > 0) {
-			for (i = 0; i < axid->bufnum1; i++) {
-				scfg->statsBuf[i] =
-					(uint32_t)(regptr->paddr);
-				regptr++;
+				if (!sack) {
+					pr_err("%s: no mem for cmd->cmd_type = %d",
+					 __func__, cmd->cmd_type);
+					return -ENOMEM;
+				}
+				sack->nextStatsBuf = *(uint32_t *)data;
 			}
 		}
-		/* individual */
-		switch (cmd->cmd_type) {
-		case CMD_STATS_AEC_ENABLE:
-			rc = vfe_stats_aec_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_AF_ENABLE:
-			rc = vfe_stats_af_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_AWB_ENABLE:
-			rc = vfe_stats_awb_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_IHIST_ENABLE:
-			rc = vfe_stats_ihist_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_RS_ENABLE:
-			rc = vfe_stats_rs_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_CS_ENABLE:
-			rc = vfe_stats_cs_buf_init(vfe32_ctrl, scfg);
-			break;
-		default:
-			pr_err("%s Unsupported cmd type %d",
-				__func__, cmd->cmd_type);
-			break;
+		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+			(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+			(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+				scfg = NULL;
+				/* individual */
+				goto vfe32_config_done;
 		}
-		goto vfe32_config_done;
-	}
-	switch (cmd->cmd_type) {
-	case CMD_GENERAL:
-		rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
+		switch (cmd->cmd_type) {
+		case CMD_GENERAL:
+			rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
 		break;
-	case CMD_CONFIG_PING_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->ping = *((struct msm_free_buf *)data);
-	}
+		case CMD_CONFIG_PING_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->ping = *((struct msm_free_buf *)data);
+		}
+		break;
+		case CMD_CONFIG_PONG_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->pong = *((struct msm_free_buf *)data);
+		}
 		break;
 
-	case CMD_CONFIG_PONG_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->pong = *((struct msm_free_buf *)data);
-	}
+		case CMD_CONFIG_FREE_BUF_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->free_buf = *((struct msm_free_buf *)data);
+		}
 		break;
-
-	case CMD_CONFIG_FREE_BUF_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->free_buf = *((struct msm_free_buf *)data);
-	}
+		case CMD_SNAP_BUF_RELEASE:
 		break;
-	case CMD_SNAP_BUF_RELEASE:
+		default:
+			pr_err("%s Unsupported AXI configuration %x ", __func__,
+				cmd->cmd_type);
 		break;
-	case CMD_STATS_AEC_BUF_RELEASE:
-		vfe32_stats_aec_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_AF_BUF_RELEASE:
-		vfe32_stats_af_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_AWB_BUF_RELEASE:
-		vfe32_stats_awb_ack(vfe32_ctrl, sack);
-		break;
-
-	case CMD_STATS_IHIST_BUF_RELEASE:
-		vfe32_stats_ihist_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_RS_BUF_RELEASE:
-		vfe32_stats_rs_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_CS_BUF_RELEASE:
-		vfe32_stats_cs_ack(vfe32_ctrl, sack);
-		break;
-	default:
-		pr_err("%s Unsupported AXI configuration %x ", __func__,
-			cmd->cmd_type);
-		break;
+		}
 	}
 vfe32_config_done:
 	kfree(scfg);
@@ -4542,14 +4708,7 @@
 	spin_lock_init(&vfe32_ctrl->io_lock);
 	spin_lock_init(&vfe32_ctrl->update_ack_lock);
 	spin_lock_init(&vfe32_ctrl->start_ack_lock);
-
-	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe32_ctrl->af_ack_lock);
-	spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
-	spin_lock_init(&vfe32_ctrl->rs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->cs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
+	spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
 
 	vfe32_ctrl->update_linear = false;
 	vfe32_ctrl->update_rolloff = false;
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index c41df09..542bbf8 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -14,6 +14,7 @@
 #define __MSM_VFE32_H__
 
 #include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
 
 #define TRUE  1
 #define FALSE 0
@@ -912,8 +913,6 @@
 #define VFE32_OUTPUT_MODE_TERTIARY2		BIT(11)
 
 struct vfe_stats_control {
-	uint8_t  ackPending;
-	uint32_t nextFrameAddrBuf;
 	uint32_t droppedStatsFrameCount;
 	uint32_t bufToRender;
 };
@@ -966,15 +965,7 @@
 	spinlock_t  start_ack_lock;
 	spinlock_t  state_lock;
 	spinlock_t  io_lock;
-
-	spinlock_t  aec_ack_lock;
-	spinlock_t  awb_ack_lock;
-	spinlock_t  af_ack_lock;
-	spinlock_t  ihist_ack_lock;
-	spinlock_t  rs_ack_lock;
-	spinlock_t  cs_ack_lock;
-	spinlock_t  comp_stats_ack_lock;
-
+	spinlock_t  stats_bufq_lock;
 	uint32_t extlen;
 	void *extdata;
 
@@ -1013,6 +1004,8 @@
 	uint32_t frame_skip_cnt;
 	uint32_t frame_skip_pattern;
 	uint32_t snapshot_frame_cnt;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
 };
 
 #define statsAeNum      0
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 398621f..5fef610 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -351,6 +351,221 @@
 static uint32_t raw_mode;
 static struct vfe2x_ctrl_type *vfe2x_ctrl;
 
+static unsigned long vfe2x_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+
+	rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
+							  stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			   __func__, stats_type, rc);
+		return 0;
+	}
+	return buf->paddr;
+}
+
+static unsigned long vfe2x_stats_flush_enqueue(
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+	rc = vfe2x_ctrl->stats_ops.bufq_flush(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			 __func__, stats_type, rc);
+		return 0L;
+	}
+
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe2x_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				vfe2x_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+			if (rc < 0) {
+				pr_err("%s: dq stats buf (type = %d) err = %d",
+					 __func__, stats_type, rc);
+				return rc;
+			}
+	}
+	return 0L;
+}
+
+static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
+{
+	unsigned long flags;
+	int i = 0, rc = 0;
+	if (type == MSM_STATS_TYPE_AF) {
+		spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+		rc = vfe2x_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				 __func__, rc);
+			spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock,
+				flags);
+			return -EINVAL;
+		}
+		spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+	}
+	for (i = 0; i < 3; i++) {
+		spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+		if (type == MSM_STATS_TYPE_AE_AW)
+			vfe2x_ctrl->stats_we_buf_ptr[i] =
+				vfe2x_stats_dqbuf(type);
+		else
+			vfe2x_ctrl->stats_af_buf_ptr[i] =
+				vfe2x_stats_dqbuf(type);
+		spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+		if (!vfe2x_ctrl->stats_we_buf_ptr[i]) {
+			pr_err("%s: dq error type %d ", __func__, type);
+			return -ENOMEM;
+		}
+	}
+	return rc;
+}
+
+static unsigned long vfe2x_stats_enqueuebuf(
+	struct msm_stats_buf_info *info, struct vfe_stats_ack *sack)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+
+	bufq = vfe2x_ctrl->stats_ctrl.bufq[info->type];
+	stats_buf = &bufq->bufs[info->buf_idx];
+
+	CDBG("vfe2x_stats_enqueuebuf: %d\n", stats_buf->state);
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED ||
+		stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				&vfe2x_ctrl->stats_ctrl,
+				info, vfe2x_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
+				 __func__, info->type, info->buf_idx, rc);
+			return rc;
+		}
+
+	} else {
+		rc = vfe2x_ctrl->stats_ops.querybuf(
+				vfe2x_ctrl->stats_ops.stats_ctrl, info, &buf);
+		if (rc < 0) {
+			pr_err("%s: querybuf (type = %d), index : %d, err = %d",
+				__func__, info->type, info->buf_idx, rc);
+			return rc;
+	}
+		stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+	if (info->type == MSM_STATS_TYPE_AE_AW) {
+		sack->header = VFE_STATS_WB_EXP_ACK;
+		sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+	} else if (info->type == MSM_STATS_TYPE_AF) {
+		sack->header = VFE_STATS_AUTOFOCUS_ACK;
+		sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+	} else
+		pr_err("%s: Invalid stats: should never come here\n", __func__);
+	}
+	return 0L;
+}
+
+static long vfe2x_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+	void *ion_client)
+{
+	long rc = 0;
+
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+		if (!vfe2x_ctrl->stats_ops.stats_ctrl) {
+			/* stats_ctrl has not been init yet */
+			rc = msm_stats_buf_ops_init(
+					&vfe2x_ctrl->stats_ctrl,
+					(struct ion_client *)ion_client,
+					&vfe2x_ctrl->stats_ops);
+			if (rc < 0) {
+				pr_err("%s: cannot init stats ops", __func__);
+				goto end;
+			}
+			rc = vfe2x_ctrl->stats_ops.stats_ctrl_init(
+					&vfe2x_ctrl->stats_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot init stats_ctrl ops",
+					 __func__);
+				memset(&vfe2x_ctrl->stats_ops, 0,
+				sizeof(vfe2x_ctrl->stats_ops));
+				goto end;
+			}
+			if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+				/* error. the length not match */
+				pr_err("%s: stats reqbuf input size = %d,\n"
+					"struct size = %d, mismatch\n",
+					__func__, cmd->length,
+					sizeof(struct msm_stats_reqbuf));
+				rc = -EINVAL;
+				goto end;
+			}
+		}
+		rc = vfe2x_ctrl->stats_ops.reqbuf(
+				&vfe2x_ctrl->stats_ctrl,
+				(struct msm_stats_reqbuf *)cmd->value,
+				vfe2x_ctrl->stats_ops.client);
+		break;
+		case VFE_CMD_STATS_ENQUEUEBUF: {
+			if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+				/* error. the length not match */
+				pr_err("%s: stats enqueuebuf input size = %d,\n"
+					"struct size = %d, mismatch\n",
+					 __func__, cmd->length,
+					sizeof(struct msm_stats_buf_info));
+				rc = -EINVAL;
+				goto end;
+		}
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				&vfe2x_ctrl->stats_ctrl,
+				(struct msm_stats_buf_info *)cmd->value,
+				vfe2x_ctrl->stats_ops.client);
+	}
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mismatch\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+				rc = -EINVAL;
+				goto end;
+		}
+		rc = vfe2x_ctrl->stats_ops.bufq_flush(
+				&vfe2x_ctrl->stats_ctrl,
+				(enum msm_stats_enum_type)flush_req->stats_type,
+				vfe2x_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported",
+			 __func__, cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static void vfe2x_send_isp_msg(
 	struct vfe2x_ctrl_type *vctrl,
 	uint32_t isp_msg_id)
@@ -384,11 +599,26 @@
 static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
 {
 	struct isp_msg_stats msg_stats;
+	void *vaddr = NULL;
+	int rc;
 
 	msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
 	msg_stats.buffer       = buf_addr;
 	msg_stats.id           = msg_id;
 
+	if (MSG_ID_STATS_AWB_AEC == msg_id)
+		rc = vfe2x_ctrl->stats_ops.dispatch(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			MSM_STATS_TYPE_AE_AW, buf_addr,
+			&msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+			vfe2x_ctrl->stats_ops.client);
+	else if (MSG_ID_STATS_AF == msg_id)
+		rc = vfe2x_ctrl->stats_ops.dispatch(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			MSM_STATS_TYPE_AF, buf_addr,
+			&msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+			vfe2x_ctrl->stats_ops.client);
+
 	v4l2_subdev_notify(&vfe2x_ctrl->subdev,
 				NOTIFY_VFE_MSG_STATS,
 				&msg_stats);
@@ -979,21 +1209,54 @@
 
 	CDBG("msm_vfe_subdev_ioctl is called\n");
 	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
-	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
-	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
 		cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE) {
+		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
+		cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
+		cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+		cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
 		if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
+			   (void __user *)(cmd->value),
+			   sizeof(vfecmd))) {
 			pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
 			return -EFAULT;
 		}
 	}
-
 	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+		return rc;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+		if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats enqueuebuf input size = %d,\n"
+				"struct size = %d, mitch match\n",\
+				__func__, cmd->length,
+				sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL;
+			return rc;
+		}
+		sack.header = 0;
+		sack.bufaddr = NULL;
+		rc = vfe2x_stats_enqueuebuf(cmd->value, &sack);
+		if (rc < 0) {
+			pr_err("%s: error", __func__);
+			rc = -EINVAL;
+			return rc;
+		}
+		if (sack.header != 0 && sack.bufaddr != NULL) {
+			queue  = QDSP_CMDQUEUE;
+			vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+			cmd_data = &sack;
+		} else {
+			return 0;
+		}
+	break;
 	case CMD_VFE_BUFFER_RELEASE: {
 		if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
 			return 0;
@@ -1041,7 +1304,6 @@
 	}
 		return 0;
 
-	case CMD_STATS_AEC_AWB_ENABLE:
 	case CMD_STATS_AXI_CFG: {
 		axid = data;
 		if (!axid) {
@@ -1096,15 +1358,49 @@
 		}
 	}
 		break;
-	case CMD_STATS_AF_ENABLE:
-	case CMD_STATS_AF_AXI_CFG: {
-		CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
+	case CMD_STATS_AEC_AWB_ENABLE: {
+		pr_err("CMD_STATS_AEC_AWB_ENABLE\n");
+		scfg =
+			kmalloc(sizeof(struct vfe_stats_we_cfg),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
 			goto config_failure;
 		}
 
+		if (copy_from_user((char *)scfg + 4,
+					(void __user *)(vfecmd.value),
+					vfecmd.length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+		*(uint32_t *)scfg = header;
+		rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AE_AW);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				 __func__);
+			goto config_failure;
+		}
+		scfg->wb_expstatoutputbuffer[0] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[0];
+		scfg->wb_expstatoutputbuffer[1] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[1];
+		scfg->wb_expstatoutputbuffer[2] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[2];
+		cmd_data = scfg;
+	}
+	break;
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG: {
+		CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
 		sfcfg =
 			kmalloc(sizeof(struct vfe_stats_af_cfg),
 				GFP_ATOMIC);
@@ -1122,9 +1418,6 @@
 			goto config_done;
 		}
 
-		CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
-			axid->bufnum1, sfcfg->af_enable);
-
 		header = cmds_map[vfecmd.id].vfe_id;
 		queue = cmds_map[vfecmd.id].queue;
 		if (header == -1 && queue == -1) {
@@ -1132,27 +1425,16 @@
 			goto config_failure;
 		}
 		*(uint32_t *)sfcfg = header;
-		CDBG("Number of buffers = %d\n", axid->bufnum1);
-		if (axid->bufnum1 > 0) {
-			regptr = &axid->region[0];
-
-			for (i = 0; i < axid->bufnum1; i++) {
-
-				CDBG("STATS_ENABLE, phy = 0x%lx\n",
-					regptr->paddr);
-
-				sfcfg->af_outbuf[i] =
-					(void *)regptr->paddr;
-
-				regptr++;
-			}
-
-			cmd_data = sfcfg;
-
-		} else {
-			rc = -EINVAL;
-			goto config_done;
+		rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AF);
+		sfcfg->af_outbuf[0] = (void *)vfe2x_ctrl->stats_af_buf_ptr[0];
+		sfcfg->af_outbuf[1] = (void *)vfe2x_ctrl->stats_af_buf_ptr[1];
+		sfcfg->af_outbuf[2] = (void *)vfe2x_ctrl->stats_af_buf_ptr[2];
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				__func__);
+			goto config_failure;
 		}
+		cmd_data = sfcfg;
 	}
 		break;
 	case CMD_SNAP_BUF_RELEASE:
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2f2d3c6..b7d6806 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -16,6 +16,7 @@
 #include <mach/camera.h>
 #include <linux/list.h>
 #include "msm.h"
+#include "msm_vfe_stats_buf.h"
 
 struct cmd_id_map {
 	uint32_t isp_id;
@@ -111,6 +112,11 @@
 	spinlock_t  sd_notify_lock;
 	uint32_t    reconfig_vfe;
 	uint32_t    zsl_mode;
+	spinlock_t  stats_bufq_lock;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
+	unsigned long stats_we_buf_ptr[3];
+	unsigned long stats_af_buf_ptr[3];
 } __packed;
 
 struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c
new file mode 100644
index 0000000..9e8f285
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.c
@@ -0,0 +1,509 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+#include <media/msm_camera.h>
+#include <media/msm_isp.h>
+#include "msm.h"
+#include "msm_vfe_stats_buf.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+	#define D(fmt, args...) pr_debug("msm_stats: " fmt, ##args)
+#else
+	#define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_stats_init(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+	int rc = 0;
+	/* cannot get spinlock here */
+	if (stats_ctrl->init_done > 0) {
+		pr_err("%s: already initialized stats ctrl. no op", __func__);
+		return 0;
+	}
+	memset(stats_ctrl,  0,  sizeof(struct msm_stats_bufq_ctrl));
+	spin_lock_init(&stats_ctrl->lock);
+	stats_ctrl->init_done = 1;
+	return rc;
+}
+
+static int msm_stats_reqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_reqbuf *reqbuf,
+	struct ion_client *client)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq;
+	struct msm_stats_meta_buf *bufs;
+	int idx = reqbuf->stats_type;
+	int i;
+
+	D("%s: type : %d, buf num : %d\n", __func__,
+		reqbuf->stats_type, reqbuf->num_buf);
+	if (reqbuf->num_buf > 0) {
+		if (stats_ctrl->bufq[idx]) {
+			/* already in use. Error */
+			pr_err("%s: stats type %d aleady requested",
+				 __func__, reqbuf->stats_type);
+			rc = -EEXIST;
+			goto end;
+		} else {
+			/* good case */
+			bufq = (struct msm_stats_bufq *)
+				kzalloc(
+					sizeof(struct msm_stats_bufq),
+					GFP_KERNEL);
+			if (!bufq) {
+				/* no memory */
+				rc = -ENOMEM;
+				pr_err("%s: no mem for stats type %d",
+					__func__, reqbuf->stats_type);
+				goto end;
+			}
+			bufs = (struct msm_stats_meta_buf *)
+				kzalloc((reqbuf->num_buf *
+					sizeof(struct msm_stats_meta_buf)),
+					GFP_KERNEL);
+			if (!bufs) {
+				/* no memory */
+				rc = -ENOMEM;
+				pr_err("%s: no mem for stats buf, stats type = %d",
+					__func__, reqbuf->stats_type);
+				kfree(bufq);
+				goto end;
+			}
+			/* init bufq list head */
+			INIT_LIST_HEAD(&bufq->head);
+			/* set the meta buf state to initialized */
+			bufq->num_bufs = reqbuf->num_buf;
+			for (i = 0; i < reqbuf->num_buf; i++)
+				bufs[i].state =
+					MSM_STATS_BUFFER_STATE_INITIALIZED;
+			bufq->bufs = bufs;
+			bufq->num_bufs = reqbuf->num_buf;
+			bufq->type = reqbuf->stats_type;
+			stats_ctrl->bufq[idx] = bufq;
+			/* done reqbuf (larger than zero case) */
+			goto end;
+		}
+	} else if (reqbuf->num_buf == 0) {
+		if (stats_ctrl->bufq[idx] == NULL) {
+			/* double free case? */
+			pr_err("%s: stats type %d aleady freed",
+				 __func__, reqbuf->stats_type);
+			rc = -ENXIO;
+			goto end;
+		} else {
+			/* good case. need to de-reqbuf */
+			kfree(stats_ctrl->bufq[idx]->bufs);
+			kfree(stats_ctrl->bufq[idx]);
+			stats_ctrl->bufq[idx] = NULL;
+			goto end;
+		}
+	} else {
+		/* error case */
+		pr_err("%s: stats type = %d, req_num_buf = %d, error",
+			   __func__, reqbuf->stats_type, reqbuf->num_buf);
+		rc = -EPERM;
+		goto end;
+	}
+end:
+	return rc;
+}
+static int msm_stats_deinit(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+	int rc = 0;
+	int i;
+
+	if (stats_ctrl->init_done == 0) {
+		pr_err("%s: not inited yet. no op", __func__);
+		return 0;
+	}
+	/* safe guard in case deallocate memory not done yet. */
+	for (i = 0; i < MSM_STATS_TYPE_MAX; i++) {
+		if (stats_ctrl->bufq[i]) {
+			if (stats_ctrl->bufq[i]->bufs) {
+				rc = -1;
+				pr_err("%s: stats type = %d, buf not freed yet",
+					 __func__, i);
+				BUG_ON(stats_ctrl->bufq[i]->bufs);
+			} else {
+				rc = -1;
+				pr_err("%s: stats type = %d, bufq not freed yet",
+					__func__, i);
+				BUG_ON(stats_ctrl->bufq[i]);
+			}
+		}
+	}
+	memset(stats_ctrl,  0,  sizeof(struct msm_stats_bufq_ctrl));
+	return rc;
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
+{
+	if (info->offset < len &&
+		info->offset + info->len <= len &&
+		info->planar0_off < len && info->planar1_off < len)
+		return 0;
+
+	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+		   __func__,
+		   info->offset,
+		   info->len,
+		   info->planar0_off,
+		   info->planar1_off,
+		   len);
+	return -EINVAL;
+}
+#endif
+
+static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info, struct ion_client *client)
+{
+	unsigned long paddr;
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	unsigned long kvstart;
+	struct file *file;
+#endif
+	int rc = 0;
+	unsigned long len;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d, buf num : %d\n", __func__,
+		info->type, info->buf_idx);
+
+	bufq = stats_ctrl->bufq[info->type];
+	stats_buf = &bufq->bufs[info->buf_idx];
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+		pr_err("%s: need reqbuf first, stats type = %d",
+			__func__, info->type);
+		rc = -1;
+		goto out1;
+	}
+	if (stats_buf->state != MSM_STATS_BUFFER_STATE_INITIALIZED) {
+		D("%s: stats already mapped, no op, stats type = %d",
+			__func__, info->type);
+		goto out1;
+	}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	stats_buf->handle = ion_import_dma_buf(client, info->fd);
+	if (IS_ERR_OR_NULL(stats_buf->handle)) {
+		rc = -EINVAL;
+		pr_err("%s: stats_buf has null/error ION handle %p",
+			   __func__, stats_buf->handle);
+		goto out1;
+	}
+	if (ion_map_iommu(client, stats_buf->handle,
+			CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+			0, &paddr, &len, UNCACHED, 0) < 0) {
+		rc = -EINVAL;
+		pr_err("%s: cannot map address", __func__);
+		goto out2;
+	}
+#elif CONFIG_ANDROID_PMEM
+	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %d error %d\n",
+			   __func__, info->fd, rc);
+		goto out1;
+	}
+	stats_buf->file = file;
+#else
+	paddr = 0;
+	file = NULL;
+	kvstart = 0;
+#endif
+	if (!info->len)
+		info->len = len;
+	rc = msm_stats_check_pmem_info(info, len);
+	if (rc < 0) {
+		pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
+		goto out3;
+	}
+	paddr += info->offset;
+	len = info->len;
+	stats_buf->paddr = paddr;
+	stats_buf->len = len;
+	memcpy(&stats_buf->info, info, sizeof(stats_buf->info));
+	D("%s Adding buf to list with type %d\n", __func__,
+	  stats_buf->info.type);
+	D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
+	stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+	return 0;
+out3:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
+	ion_free(client, stats_buf->handle);
+#elif CONFIG_ANDROID_PMEM
+	put_pmem_file(stats_buf->file);
+#endif
+out1:
+	return rc;
+}
+static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type, int buf_idx,
+	struct ion_client *client)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d, idx : %d\n", __func__, stats_type, buf_idx);
+	bufq = stats_ctrl->bufq[stats_type];
+	stats_buf = &bufq->bufs[buf_idx];
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+		pr_err("%s: need reqbuf first, stats type = %d",
+			__func__, stats_type);
+		rc = -1;
+		goto end;
+	}
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED) {
+		D("%s: stats already mapped, no op, stats type = %d",
+			__func__, stats_type);
+		goto end;
+	}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(client, stats_buf->handle,
+					CAMERA_DOMAIN, GEN_POOL);
+	ion_free(client, stats_buf->handle);
+#else
+	put_pmem_file(stats_buf->file);
+#endif
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+		/* buf queued need delete from list */
+		D("%s: delete stats buf, type = %d, idx = %d",
+		  __func__,  stats_type,  buf_idx);
+		list_del_init(&stats_buf->list);
+	}
+end:
+	return rc;
+}
+
+static int msm_stats_bufq_flush(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type, struct ion_client *client)
+{
+	int rc = 0;
+	int i;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d\n", __func__, stats_type);
+	bufq = stats_ctrl->bufq[stats_type];
+
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		switch (stats_buf->state) {
+		case MSM_STATS_BUFFER_STATE_QUEUED:
+			/* buf queued in stats free queue */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			list_del_init(&stats_buf->list);
+			break;
+		case MSM_STATS_BUFFER_STATE_DEQUEUED:
+			/* if stats buf in VFE reset the state */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			break;
+		case MSM_STATS_BUFFER_STATE_DISPATCHED:
+			/* if stats buf in userspace reset the state */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			break;
+		default:
+			break;
+		}
+	}
+	return rc;
+}
+
+static int msm_stats_dqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	struct msm_stats_meta_buf **pp_stats_buf)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d\n", __func__, stats_type);
+	*pp_stats_buf = NULL;
+	bufq = stats_ctrl->bufq[stats_type];
+
+	list_for_each_entry(stats_buf, &bufq->head, list) {
+		if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+			/* found one buf */
+			list_del_init(&stats_buf->list);
+			*pp_stats_buf = stats_buf;
+			break;
+		}
+	}
+	if (!(*pp_stats_buf)) {
+		pr_err("%s: no free stats buf, type = %d",
+			__func__, stats_type);
+		rc = -1;
+		return rc;
+	}
+	stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+	return rc;
+}
+
+
+static int msm_stats_querybuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info,
+	struct msm_stats_meta_buf **pp_stats_buf)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+
+	*pp_stats_buf = NULL;
+	D("%s: stats type : %d, buf_idx : %d", __func__, info->type,
+		   info->buf_idx);
+	bufq = stats_ctrl->bufq[info->type];
+	*pp_stats_buf = &bufq->bufs[info->buf_idx];
+
+	return rc;
+}
+
+static int msm_stats_qbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	int buf_idx)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	D("%s: stats type : %d, buf_idx : %d", __func__, stats_type,
+		   buf_idx);
+
+	bufq = stats_ctrl->bufq[stats_type];
+	if (!bufq) {
+		pr_err("%s: null bufq, stats type = %d", __func__, stats_type);
+		rc = -1;
+		goto end;
+	}
+	if (buf_idx >= bufq->num_bufs) {
+		pr_err("%s: stats type = %d, its idx %d larger than buf count %d",
+			   __func__, stats_type, buf_idx, bufq->num_bufs);
+		rc = -1;
+		goto end;
+	}
+	stats_buf = &bufq->bufs[buf_idx];
+	switch (stats_buf->state) {
+	case MSM_STATS_BUFFER_STATE_PREPARED:
+	case MSM_STATS_BUFFER_STATE_DEQUEUED:
+	case MSM_STATS_BUFFER_STATE_DISPATCHED:
+		stats_buf->state = MSM_STATS_BUFFER_STATE_QUEUED;
+		list_add_tail(&stats_buf->list, &bufq->head);
+		break;
+	default:
+		pr_err("%s: incorrect state = %d, stats type = %d, cannot qbuf",
+			   __func__, stats_buf->state, stats_type);
+		rc = -1;
+		break;
+	}
+end:
+	return rc;
+}
+
+static int msm_stats_buf_dispatch(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	unsigned long phy_addr, int *buf_idx,
+	void **vaddr, int *fd,
+	struct ion_client *client)
+{
+	int rc = 0;
+	int i;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	D("%s: stats type : %d\n", __func__, stats_type);
+
+	*buf_idx = -1;
+	*vaddr = NULL;
+	*fd = 0;
+	bufq = stats_ctrl->bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		if (bufq->bufs[i].paddr == phy_addr) {
+			stats_buf = &bufq->bufs[i];
+			*buf_idx = i;
+			*vaddr = stats_buf->info.vaddr;
+			*fd = stats_buf->info.fd;
+			break;
+		}
+	}
+	if (!stats_buf) {
+		pr_err("%s: no match, phy_addr = 0x%ld, stats_type = %d",
+			   __func__, phy_addr, stats_type);
+		return -EFAULT;
+	}
+	switch (stats_buf->state) {
+	case MSM_STATS_BUFFER_STATE_DEQUEUED:
+		stats_buf->state = MSM_STATS_BUFFER_STATE_DISPATCHED;
+		break;
+	default:
+		pr_err("%s: type = %d, idx = %d, cur_state = %d,\n"
+			   "cannot set state to DISPATCHED\n",
+			   __func__, stats_type, *buf_idx, stats_buf->state);
+		rc = -EFAULT;
+		break;
+	}
+	return rc;
+}
+static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info, struct ion_client *client)
+{
+	int rc = 0;
+	rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+	if (rc < 0) {
+		pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
+		return -EINVAL;
+	}
+	rc = msm_stats_qbuf(stats_ctrl,   info->type, info->buf_idx);
+	if (rc < 0) {
+		pr_err("%s: msm_stats_qbuf failed, rc = %d", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct ion_client *client, struct msm_stats_ops *ops)
+{
+	ops->stats_ctrl = stats_ctrl;
+	ops->client = client;
+	ops->enqueue_buf = msm_stats_enqueue_buf;
+	ops->qbuf = msm_stats_qbuf;
+	ops->dqbuf = msm_stats_dqbuf;
+	ops->bufq_flush = msm_stats_bufq_flush;
+	ops->buf_unprepare = msm_stats_buf_unprepare;
+	ops->buf_prepare = msm_stats_buf_prepare;
+	ops->reqbuf = msm_stats_reqbuf;
+	ops->querybuf = msm_stats_querybuf;
+	ops->dispatch = msm_stats_buf_dispatch;
+	ops->stats_ctrl_init = msm_stats_init;
+	ops->stats_ctrl_deinit = msm_stats_deinit;
+	return 0;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.h b/drivers/media/video/msm/msm_vfe_stats_buf.h
new file mode 100644
index 0000000..18fd425
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#ifndef _MSM_STATS_BUF_H_
+#define _MSM_STATS_BUF_H_
+
+enum msm_stats_buffer_state {
+	MSM_STATS_BUFFER_STATE_UNUSED,	  /* not used */
+	MSM_STATS_BUFFER_STATE_INITIALIZED,	   /* REQBUF done */
+	MSM_STATS_BUFFER_STATE_PREPARED,	/* BUF mapped */
+	MSM_STATS_BUFFER_STATE_QUEUED,	  /* buf queued */
+	MSM_STATS_BUFFER_STATE_DEQUEUED,	/* in use in VFE */
+	MSM_STATS_BUFFER_STATE_DISPATCHED,	  /* sent to userspace */
+};
+
+struct msm_stats_meta_buf {
+	struct list_head list;
+	enum msm_stats_buffer_state state;
+	int type;
+	int fd;
+	uint32_t offset;
+	unsigned long paddr;
+	unsigned long len;
+	struct file *file;
+	struct msm_stats_buf_info info;
+	struct ion_handle *handle;
+};
+
+struct msm_stats_bufq {
+	struct list_head head;
+	int num_bufs;
+	int type;
+	struct msm_stats_meta_buf *bufs;
+};
+
+
+struct msm_stats_bufq_ctrl {
+	/* not use spin lock for now. Assume vfe holds spin lock */
+	spinlock_t lock;
+	int init_done;
+	struct msm_stats_bufq *bufq[MSM_STATS_TYPE_MAX];
+};
+
+struct msm_stats_ops {
+	struct msm_stats_bufq_ctrl *stats_ctrl;
+	struct ion_client *client;
+	int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+						struct msm_stats_buf_info *info,
+						struct ion_client *client);
+	int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				 enum msm_stats_enum_type stats_type,
+				 int buf_idx);
+	int (*dqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				  enum msm_stats_enum_type stats_type,
+				  struct msm_stats_meta_buf **pp_stats_buf);
+	int (*bufq_flush) (struct msm_stats_bufq_ctrl *stats_ctrl,
+					   enum msm_stats_enum_type stats_type,
+					   struct ion_client *client);
+	int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		enum msm_stats_enum_type stats_type,
+		int buf_idx,
+		struct ion_client *client);
+	int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+						struct msm_stats_buf_info *info,
+						struct ion_client *client);
+	int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				   struct msm_stats_reqbuf *reqbuf,
+				   struct ion_client *client);
+	int (*dispatch) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		enum msm_stats_enum_type stats_type,
+		unsigned long phy_addr, int *buf_idx, void **vaddr, int *fd,
+		struct ion_client *client);
+	int (*querybuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		struct msm_stats_buf_info *info,
+		struct msm_stats_meta_buf **pp_stats_buf);
+	int (*stats_ctrl_init) (struct msm_stats_bufq_ctrl *stats_ctrl);
+	int (*stats_ctrl_deinit) (struct msm_stats_bufq_ctrl *stats_ctrl);
+};
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct ion_client *client, struct msm_stats_ops *ops);
+
+#endif /* _MSM_STATS_BUF_H_ */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 81b6a40..48058e6 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -195,6 +195,24 @@
 #define MSM_CAM_IOCTL_ISPIF_IO_CFG \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
 
+#define MSM_CAM_IOCTL_STATS_REQBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *)
+
+#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *)
+
+#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+
+struct msm_stats_reqbuf {
+	int num_buf;		/* how many buffers requested */
+	int stats_type;	/* stats type */
+};
+
+struct msm_stats_flush_bufq {
+	int stats_type;	/* enum msm_stats_enum_type */
+};
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
@@ -515,6 +533,36 @@
 #define FRAME_RAW_SNAPSHOT		4
 #define FRAME_MAX			5
 
+enum msm_stats_enum_type {
+	MSM_STATS_TYPE_AEC, /* legacy based AEC */
+	MSM_STATS_TYPE_AF,  /* legacy based AF */
+	MSM_STATS_TYPE_AWB, /* legacy based AWB */
+	MSM_STATS_TYPE_RS,  /* legacy based RS */
+	MSM_STATS_TYPE_CS,  /* legacy based CS */
+	MSM_STATS_TYPE_IHIST,   /* legacy based HIST */
+	MSM_STATS_TYPE_SKIN,    /* legacy based SKIN */
+	MSM_STATS_TYPE_BG,  /* Bayer Grids */
+	MSM_STATS_TYPE_BF,  /* Bayer Focus */
+	MSM_STATS_TYPE_BHIST,   /* Bayer Hist */
+	MSM_STATS_TYPE_AE_AW,   /* legacy stats for vfe 2.x*/
+	MSM_STATS_TYPE_MAX  /* MAX */
+};
+
+struct msm_stats_buf_info {
+	int type; /* msm_stats_enum_type */
+	int fd;
+	void *vaddr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint8_t active;
+	int buf_idx;
+};
+
 struct msm_pmem_info {
 	int type;
 	int fd;
@@ -678,6 +726,7 @@
 	int length;
 	struct ion_handle *handle;
 	uint32_t frame_id;
+	int buf_idx;
 };
 #define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
 /* video capture mode in VIDIOC_S_PARM */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 6547795..1f3527b 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -203,6 +203,9 @@
 #define VFE_CMD_CAPTURE_RAW                             136
 #define VFE_CMD_STOP_LIVESHOT                           137
 #define VFE_CMD_RECONFIG_VFE                            138
+#define VFE_CMD_STATS_REQBUF                            139
+#define VFE_CMD_STATS_ENQUEUEBUF                        140
+#define VFE_CMD_STATS_FLUSH_BUFQ                        141
 
 struct msm_isp_cmd {
 	int32_t  id;