Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 43f696e9 authored by Peter Liu's avatar Peter Liu Committed by Stephen Boyd
Browse files

msm: camera: Add per instance lock in to serialize



Add per instance lock to serialize stream operation.
Protect unpredicted crash on video recording by serializing ops.
Instead of only using the vid_lock to protect the video node,
we need inst lock to serialize the stream operation, too.
This commit increases the stability during recording.

Change-Id: I4f6dcb6637eb700df04f30a102aada4fdec9f2d1
CRs-Fixed: 363221
Signed-off-by: default avatarPeter Liu <pingchie@codeaurora.org>
parent cc95af00
Loading
Loading
Loading
Loading
+48 −6
Original line number Diff line number Diff line
@@ -166,17 +166,22 @@ static int msm_camera_v4l2_reqbufs(struct file *f, void *pctx,
		struct msm_cam_v4l2_dev_inst, eventHandle);
	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam_inst->inst_lock);
	rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
	if (rc < 0) {
		pr_err("%s reqbufs failed %d ", __func__, rc);
		mutex_unlock(&pcam_inst->inst_lock);
		return rc;
	}
	if (!pb->count) {
		/* Deallocation. free buf_offset array */
		D("%s Inst %p freeing buffer offsets array",
			__func__, pcam_inst);
		for (j = 0 ; j < pcam_inst->buf_count ; j++)
		for (j = 0 ; j < pcam_inst->buf_count ; j++) {
			kfree(pcam_inst->buf_offset[j]);
			pcam_inst->buf_offset[j] = NULL;
		}
		kfree(pcam_inst->buf_offset);
		pcam_inst->buf_offset = NULL;
		/* If the userspace has deallocated all the
@@ -194,6 +199,7 @@ static int msm_camera_v4l2_reqbufs(struct file *f, void *pctx,
							GFP_KERNEL);
		if (!pcam_inst->buf_offset) {
			pr_err("%s out of memory ", __func__);
			mutex_unlock(&pcam_inst->inst_lock);
			return -ENOMEM;
		}
		for (i = 0; i < pb->count; i++) {
@@ -202,15 +208,19 @@ static int msm_camera_v4l2_reqbufs(struct file *f, void *pctx,
				pcam_inst->plane_info.num_planes, GFP_KERNEL);
			if (!pcam_inst->buf_offset[i]) {
				pr_err("%s out of memory ", __func__);
				for (j = i-1 ; j >= 0; j--)
				for (j = i-1 ; j >= 0; j--) {
					kfree(pcam_inst->buf_offset[j]);
					pcam_inst->buf_offset[j] = NULL;
				}
				kfree(pcam_inst->buf_offset);
				pcam_inst->buf_offset = NULL;
				mutex_unlock(&pcam_inst->inst_lock);
				return -ENOMEM;
			}
		}
	}
	pcam_inst->buf_count = pb->count;
	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -218,13 +228,17 @@ static int msm_camera_v4l2_querybuf(struct file *f, void *pctx,
					struct v4l2_buffer *pb)
{
	/* get the video device */
	int rc = 0;
	struct msm_cam_v4l2_dev_inst *pcam_inst;
	pcam_inst = container_of(f->private_data,
		struct msm_cam_v4l2_dev_inst, eventHandle);

	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);
	return vb2_querybuf(&pcam_inst->vid_bufq, pb);
	mutex_lock(&pcam_inst->inst_lock);
	rc = vb2_querybuf(&pcam_inst->vid_bufq, pb);
	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
@@ -240,8 +254,10 @@ static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
		pcam_inst->image_mode, pb->index);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam_inst->inst_lock);
	if (!pcam_inst->buf_offset) {
		pr_err("%s Buffer is already released. Returning.\n", __func__);
		mutex_unlock(&pcam_inst->inst_lock);
		return -EINVAL;
	}

@@ -249,6 +265,7 @@ static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
		/* Reject the buffer if planes array was not allocated */
		if (pb->m.planes == NULL) {
			pr_err("%s Planes array is null\n", __func__);
			mutex_unlock(&pcam_inst->inst_lock);
			return -EINVAL;
		}
		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -269,7 +286,7 @@ static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
	rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
	D("%s, videobuf_qbuf mode %d and idx %d returns %d\n", __func__,
		pcam_inst->image_mode, pb->index, rc);

	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -285,6 +302,11 @@ static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx,
	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam_inst->inst_lock);
	if (0 == pcam_inst->streamon) {
		mutex_unlock(&pcam_inst->inst_lock);
		return -EACCES;
	}
	rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb,  f->f_flags & O_NONBLOCK);
	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);

@@ -292,6 +314,7 @@ static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx,
		/* Reject the buffer if planes array was not allocated */
		if (pb->m.planes == NULL) {
			pr_err("%s Planes array is null\n", __func__);
			mutex_unlock(&pcam_inst->inst_lock);
			return -EINVAL;
		}
		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -309,6 +332,7 @@ static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx,
		pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
	}

	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -325,9 +349,13 @@ static int msm_camera_v4l2_streamon(struct file *f, void *pctx,
	D("%s Inst %p\n", __func__, pcam_inst);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam->vid_lock);
	mutex_lock(&pcam_inst->inst_lock);
	if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
		(buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
		pr_err("%s Invalid buffer type ", __func__);
		mutex_unlock(&pcam_inst->inst_lock);
		mutex_unlock(&pcam->vid_lock);
		return -EINVAL;
	}

@@ -336,10 +364,10 @@ static int msm_camera_v4l2_streamon(struct file *f, void *pctx,
	rc = vb2_streamon(&pcam_inst->vid_bufq, buf_type);
	D("%s, videobuf_streamon returns %d\n", __func__, rc);

	mutex_lock(&pcam->vid_lock);
	/* turn HW (VFE/sensor) streaming */
	pcam_inst->streamon = 1;
	rc = msm_server_streamon(pcam, pcam_inst->my_index);
	mutex_unlock(&pcam_inst->inst_lock);
	mutex_unlock(&pcam->vid_lock);
	D("%s rc = %d\n", __func__, rc);
	return rc;
@@ -367,16 +395,20 @@ static int msm_camera_v4l2_streamoff(struct file *f, void *pctx,
	/* first turn of HW (VFE/sensor) streaming so that buffers are
		not in use when we free the buffers */
	mutex_lock(&pcam->vid_lock);
	mutex_lock(&pcam_inst->inst_lock);
	pcam_inst->streamon = 0;
	if (msm_server_get_usecount() > 0)
		rc = msm_server_streamoff(pcam, pcam_inst->my_index);
	mutex_unlock(&pcam->vid_lock);

	if (rc < 0)
		pr_err("%s: hw failed to stop streaming\n", __func__);

	/* stop buffer streaming */
	rc = vb2_streamoff(&pcam_inst->vid_bufq, buf_type);
	D("%s, videobuf_streamoff returns %d\n", __func__, rc);

	mutex_unlock(&pcam_inst->inst_lock);
	mutex_unlock(&pcam->vid_lock);
	return rc;
}

@@ -466,11 +498,13 @@ static int msm_camera_v4l2_try_fmt_cap(struct file *f, void *pctx,
	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam->vid_lock);
	rc = msm_server_try_fmt(pcam, pfmt);
	if (rc)
		pr_err("Format %x not found, rc = %d\n",
				pfmt->fmt.pix.pixelformat, rc);

	mutex_unlock(&pcam->vid_lock);
	return rc;
}

@@ -484,11 +518,13 @@ static int msm_camera_v4l2_try_fmt_cap_mplane(struct file *f, void *pctx,
	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam->vid_lock);
	rc = msm_server_try_fmt_mplane(pcam, pfmt);
	if (rc)
		pr_err("Format %x not found, rc = %d\n",
				pfmt->fmt.pix_mp.pixelformat, rc);

	mutex_unlock(&pcam->vid_lock);
	return rc;
}

@@ -795,6 +831,7 @@ static int msm_open(struct file *f)
		mutex_unlock(&pcam->vid_lock);
		return rc;
	}
	mutex_init(&pcam_inst->inst_lock);
	pcam_inst->sensor_pxlcode = pcam->usr_fmts[0].pxlcode;
	pcam_inst->my_index = i;
	pcam_inst->pcam = pcam;
@@ -887,7 +924,9 @@ msm_cam_server_begin_session_failed:
		pcam->dev_inst[i] = NULL;
		pcam->use_count = 0;
	}
	pcam->dev_inst[i] = NULL;
	mutex_unlock(&pcam->vid_lock);
	mutex_destroy(&pcam_inst->inst_lock);
	kfree(pcam_inst);
	pr_err("%s: error end", __func__);
	return rc;
@@ -986,6 +1025,7 @@ static int msm_close(struct file *f)
	}

	mutex_lock(&pcam->vid_lock);
	mutex_lock(&pcam_inst->inst_lock);

	if (pcam_inst->streamon) {
		/*something went wrong since instance
@@ -1011,6 +1051,8 @@ static int msm_close(struct file *f)
		v4l2_fh_del(&pcam_inst->eventHandle);
		v4l2_fh_exit(&pcam_inst->eventHandle);
	}
	mutex_unlock(&pcam_inst->inst_lock);
	mutex_destroy(&pcam_inst->inst_lock);
	kfree(pcam_inst);
	f->private_data = NULL;

+1 −0
Original line number Diff line number Diff line
@@ -347,6 +347,7 @@ struct msm_cam_v4l2_dev_inst {
	int is_mem_map_inst;
	struct img_plane_info plane_info;
	int vbqueue_initialized;
	struct mutex inst_lock;
};

struct msm_cam_mctl_node {
+35 −5
Original line number Diff line number Diff line
@@ -1123,17 +1123,22 @@ static int msm_mctl_v4l2_reqbufs(struct file *f, void *pctx,
		struct msm_cam_v4l2_dev_inst, eventHandle);
	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam_inst->inst_lock);
	rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
	if (rc < 0) {
		pr_err("%s reqbufs failed %d ", __func__, rc);
		mutex_unlock(&pcam_inst->inst_lock);
		return rc;
	}
	if (!pb->count) {
		/* Deallocation. free buf_offset array */
		D("%s Inst %p freeing buffer offsets array",
			__func__, pcam_inst);
		for (j = 0 ; j < pcam_inst->buf_count ; j++)
		for (j = 0 ; j < pcam_inst->buf_count ; j++) {
			kfree(pcam_inst->buf_offset[j]);
			pcam_inst->buf_offset[j] = NULL;
		}
		kfree(pcam_inst->buf_offset);
		pcam_inst->buf_offset = NULL;
		/* If the userspace has deallocated all the
@@ -1151,6 +1156,7 @@ static int msm_mctl_v4l2_reqbufs(struct file *f, void *pctx,
							GFP_KERNEL);
		if (!pcam_inst->buf_offset) {
			pr_err("%s out of memory ", __func__);
			mutex_unlock(&pcam_inst->inst_lock);
			return -ENOMEM;
		}
		for (i = 0; i < pb->count; i++) {
@@ -1159,10 +1165,13 @@ static int msm_mctl_v4l2_reqbufs(struct file *f, void *pctx,
				pcam_inst->plane_info.num_planes, GFP_KERNEL);
			if (!pcam_inst->buf_offset[i]) {
				pr_err("%s out of memory ", __func__);
				for (j = i-1 ; j >= 0; j--)
				for (j = i-1 ; j >= 0; j--) {
					kfree(pcam_inst->buf_offset[j]);
					pcam_inst->buf_offset[j] = NULL;
				}
				kfree(pcam_inst->buf_offset);
				pcam_inst->buf_offset = NULL;
				mutex_unlock(&pcam_inst->inst_lock);
				return -ENOMEM;
			}
		}
@@ -1170,6 +1179,7 @@ static int msm_mctl_v4l2_reqbufs(struct file *f, void *pctx,
	pcam_inst->buf_count = pb->count;
	D("%s inst %p, buf count %d ", __func__,
		pcam_inst, pcam_inst->buf_count);
	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -1177,13 +1187,17 @@ static int msm_mctl_v4l2_querybuf(struct file *f, void *pctx,
					struct v4l2_buffer *pb)
{
	/* get the video device */
	int rc = 0;
	struct msm_cam_v4l2_dev_inst *pcam_inst;
	pcam_inst = container_of(f->private_data,
		struct msm_cam_v4l2_dev_inst, eventHandle);

	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);
	return vb2_querybuf(&pcam_inst->vid_bufq, pb);
	mutex_lock(&pcam_inst->inst_lock);
	rc = vb2_querybuf(&pcam_inst->vid_bufq, pb);
	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

static int msm_mctl_v4l2_qbuf(struct file *f, void *pctx,
@@ -1198,8 +1212,10 @@ static int msm_mctl_v4l2_qbuf(struct file *f, void *pctx,
	D("%s Inst = %p\n", __func__, pcam_inst);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam_inst->inst_lock);
	if (!pcam_inst->buf_offset) {
		pr_err("%s Buffer is already released. Returning. ", __func__);
		mutex_unlock(&pcam_inst->inst_lock);
		return -EINVAL;
	}

@@ -1207,6 +1223,7 @@ static int msm_mctl_v4l2_qbuf(struct file *f, void *pctx,
		/* Reject the buffer if planes array was not allocated */
		if (pb->m.planes == NULL) {
			pr_err("%s Planes array is null ", __func__);
			mutex_unlock(&pcam_inst->inst_lock);
			return -EINVAL;
		}
		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -1232,6 +1249,7 @@ static int msm_mctl_v4l2_qbuf(struct file *f, void *pctx,
	rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
	D("%s, videobuf_qbuf returns %d\n", __func__, rc);

	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -1246,10 +1264,16 @@ static int msm_mctl_v4l2_dqbuf(struct file *f, void *pctx,

	D("%s\n", __func__);
	WARN_ON(pctx != f->private_data);
	mutex_lock(&pcam_inst->inst_lock);
	if (0 == pcam_inst->streamon) {
		mutex_unlock(&pcam_inst->inst_lock);
		return -EACCES;
	}

	rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb,  f->f_flags & O_NONBLOCK);
	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);

	mutex_unlock(&pcam_inst->inst_lock);
	return rc;
}

@@ -1266,9 +1290,13 @@ static int msm_mctl_v4l2_streamon(struct file *f, void *pctx,
	D("%s Inst %p\n", __func__, pcam_inst);
	WARN_ON(pctx != f->private_data);

	mutex_lock(&pcam->mctl_node.dev_lock);
	mutex_lock(&pcam_inst->inst_lock);
	if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
		(buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
		pr_err("%s Invalid buffer type ", __func__);
		mutex_unlock(&pcam_inst->inst_lock);
		mutex_unlock(&pcam->mctl_node.dev_lock);
		return -EINVAL;
	}

@@ -1277,9 +1305,9 @@ static int msm_mctl_v4l2_streamon(struct file *f, void *pctx,
	rc = vb2_streamon(&pcam_inst->vid_bufq, buf_type);
	D("%s, videobuf_streamon returns %d\n", __func__, rc);

	mutex_lock(&pcam->mctl_node.dev_lock);
	/* turn HW (VFE/sensor) streaming */
	pcam_inst->streamon = 1;
	mutex_unlock(&pcam_inst->inst_lock);
	mutex_unlock(&pcam->mctl_node.dev_lock);
	D("%s rc = %d\n", __func__, rc);
	return rc;
@@ -1307,14 +1335,16 @@ static int msm_mctl_v4l2_streamoff(struct file *f, void *pctx,
	/* first turn of HW (VFE/sensor) streaming so that buffers are
		not in use when we free the buffers */
	mutex_lock(&pcam->mctl_node.dev_lock);
	mutex_lock(&pcam_inst->inst_lock);
	pcam_inst->streamon = 0;
	mutex_unlock(&pcam->mctl_node.dev_lock);
	if (rc < 0)
		pr_err("%s: hw failed to stop streaming\n", __func__);

	/* stop buffer streaming */
	rc = vb2_streamoff(&pcam_inst->vid_bufq, buf_type);
	D("%s, videobuf_streamoff returns %d\n", __func__, rc);
	mutex_unlock(&pcam_inst->inst_lock);
	mutex_unlock(&pcam->mctl_node.dev_lock);
	return rc;
}

+5 −0
Original line number Diff line number Diff line
@@ -637,6 +637,7 @@ end:
		__func__, tmp_cmd.type, (uint32_t)tmp_cmd.value,
		tmp_cmd.length, tmp_cmd.status, rc);
	kfree(ctrl_data);
	ctrl_data = NULL;
	return rc;
}

@@ -2405,6 +2406,7 @@ static long msm_ioctl_config(struct file *fp, unsigned int cmd,
		/* Next, copy the userspace event ctrl structure */
		if (copy_from_user((void *)&u_isp_event, user_ptr,
				   sizeof(struct msm_isp_event_ctrl))) {
			rc = -EFAULT;
			break;
		}
		/* Save the pointer of the user allocated command buffer*/
@@ -2416,6 +2418,7 @@ static long msm_ioctl_config(struct file *fp, unsigned int cmd,
			&ev, fp->f_flags & O_NONBLOCK);
		if (rc < 0) {
			pr_err("no pending events?");
			rc = -EFAULT;
			break;
		}
		/* Use k_isp_event to point to the event_ctrl structure
@@ -2445,6 +2448,7 @@ static long msm_ioctl_config(struct file *fp, unsigned int cmd,
						break;
					}
					kfree(k_msg_value);
					k_msg_value = NULL;
				}
			}
		}
@@ -2457,6 +2461,7 @@ static long msm_ioctl_config(struct file *fp, unsigned int cmd,
			break;
		}
		kfree(k_isp_event);
		k_isp_event = NULL;

		/* Copy the v4l2_event structure back to the user*/
		if (copy_to_user((void __user *)arg, &ev,