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

Commit df88b49a authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: sde: add support for multiple commit per context" into msm-4.9

parents 2d16dbdd f94a255c
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -1887,8 +1887,9 @@ static int sde_rotator_add_request(struct sde_rot_mgr *mgr,

		INIT_WORK(&entry->commit_work, sde_rotator_commit_handler);
		INIT_WORK(&entry->done_work, sde_rotator_done_handler);
		SDEROT_DBG("Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%u\n"
			"dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->wb_idx,
		SDEROT_DBG(
			"Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%x dst{%u,%u,%u,%u}f=%x session_id=%u\n",
			item->wb_idx,
			item->src_rect.x, item->src_rect.y,
			item->src_rect.w, item->src_rect.h, item->input.format,
			item->dst_rect.x, item->dst_rect.y,
@@ -1967,8 +1968,7 @@ static void sde_rotator_free_completed_request(struct sde_rot_mgr *mgr,
	struct sde_rot_entry_container *req, *req_next;

	list_for_each_entry_safe(req, req_next, &private->req_list, list) {
		if ((atomic_read(&req->pending_count) == 0) &&
				(!req->retire_work && !req->retireq)) {
		if ((atomic_read(&req->pending_count) == 0) && req->finished) {
			list_del_init(&req->list);
			devm_kfree(&mgr->pdev->dev, req);
		}
@@ -2139,7 +2139,7 @@ static int sde_rotator_close_session(struct sde_rot_mgr *mgr,
	sde_rotator_update_clk(mgr);
	sde_rotator_resource_ctrl(mgr, false);
done:
	SDEROT_DBG("Closed session id:%u", id);
	SDEROT_DBG("Closed session id:%u\n", id);
	return 0;
}

@@ -2230,14 +2230,25 @@ struct sde_rot_entry_container *sde_rotator_req_init(
	return req;
}

void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rot_entry_container *req)
{
	if (!mgr || !private || !req) {
		SDEROT_ERR("null parameters\n");
		return;
	}

	req->finished = true;
}

int sde_rotator_handle_request_common(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rot_entry_container *req,
	struct sde_rotation_item *items)
	struct sde_rot_entry_container *req)
{
	int ret;

	if (!mgr || !private || !req || !items) {
	if (!mgr || !private || !req) {
		SDEROT_ERR("null parameters\n");
		return -EINVAL;
	}
+140 −6
Original line number Diff line number Diff line
@@ -66,6 +66,13 @@
 * configuration structures
 **********************************************************************/

/*
 * struct sde_rotation_buf_info - input/output buffer configuration
 * @width: width of buffer region to be processed
 * @height: height of buffer region to be processed
 * @format: pixel format of buffer
 * @comp_ratio: compression ratio for the session
 */
struct sde_rotation_buf_info {
	uint32_t width;
	uint32_t height;
@@ -73,6 +80,14 @@ struct sde_rotation_buf_info {
	struct sde_mult_factor comp_ratio;
};

/*
 * struct sde_rotation_config - rotation configuration for given session
 * @session_id: identifier of the given session
 * @input: input buffer information
 * @output: output buffer information
 * @frame_rate: session frame rate in fps
 * @flags: configuration flags, e.g. rotation angle, flip, etc...
 */
struct sde_rotation_config {
	uint32_t	session_id;
	struct sde_rotation_buf_info	input;
@@ -191,6 +206,18 @@ struct sde_rot_queue {
	struct sde_rot_hw_resource *hw;
};

/*
 * struct sde_rot_entry_container - rotation request
 * @list: list of active requests managed by rotator manager
 * @flags: reserved
 * @count: size of rotation entries
 * @pending_count: count of entries pending completion
 * @failed_count: count of entries failed completion
 * @finished: true if client is finished with the request
 * @retireq: workqueue to post completion notification
 * @retire_work: work for completion notification
 * @entries: array of rotation entries
 */
struct sde_rot_entry_container {
	struct list_head list;
	u32 flags;
@@ -199,6 +226,7 @@ struct sde_rot_entry_container {
	atomic_t failed_count;
	struct workqueue_struct *retireq;
	struct work_struct *retire_work;
	bool finished;
	struct sde_rot_entry *entries;
};

@@ -380,61 +408,167 @@ static inline int __compare_session_rotations(uint32_t cfg_flag,
	return 0;
}

/*
 * sde_rotator_core_init - initialize rotator manager for the given platform
 *	device
 * @pmgr: Pointer to pointer of the newly initialized rotator manager
 * @pdev: Pointer to platform device
 * return: 0 if success; error code otherwise
 */
int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
		struct platform_device *pdev);

/*
 * sde_rotator_core_destroy - destroy given rotator manager
 * @mgr: Pointer to rotator manager
 * return: none
 */
void sde_rotator_core_destroy(struct sde_rot_mgr *mgr);

/*
 * sde_rotator_session_open - open a new rotator per file session
 * @mgr: Pointer to rotator manager
 * @pprivate: Pointer to pointer of the newly initialized per file session
 * @session_id: identifier of the newly created session
 * @queue: Pointer to fence queue of the new session
 * return: 0 if success; error code otherwise
 */
int sde_rotator_session_open(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private **pprivate, int session_id,
	struct sde_rot_queue *queue);

/*
 * sde_rotator_session_close - close the given rotator per file session
 * @mgr: Pointer to rotator manager
 * @private: Pointer to per file session
 * @session_id: identifier of the session
 * return: none
 */
void sde_rotator_session_close(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private, int session_id);

/*
 * sde_rotator_session_config - configure the given rotator per file session
 * @mgr: Pointer to rotator manager
 * @private: Pointer to  per file session
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_session_config(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rotation_config *config);

/*
 * sde_rotator_req_init - allocate a new request and initialzie with given
 *	array of rotation items
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @items: Pointer to array of rotation item
 * @count: size of rotation item array
 * @flags: rotation request flags
 * return: Pointer to new rotation request if success; ERR_PTR otherwise
 */
struct sde_rot_entry_container *sde_rotator_req_init(
	struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *private,
	struct sde_rotation_item *items,
	u32 count, u32 flags);

/*
 * sde_rotator_req_finish - notify manager that client is finished with the
 *	given request and manager can release the request as required
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: none
 */
void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_handle_request_common - add the given request to rotator
 *	manager and clean up completed requests
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: 0 if success; error code otherwise
 */
int sde_rotator_handle_request_common(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req,
	struct sde_rotation_item *items);
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_queue_request - queue/schedule the given request for h/w commit
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: 0 if success; error code otherwise
 */
void sde_rotator_queue_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

void sde_rotator_remove_request(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_verify_config_all - verify given rotation configuration
 * @rot_dev: Pointer to rotator device
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_all(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_verify_config_input - verify rotation input configuration
 * @rot_dev: Pointer to rotator device
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_input(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_verify_config_output - verify rotation output configuration
 * @rot_dev: Pointer to rotator device
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_output(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_validate_request - validates given rotation request with
 *	previous rotator configuration
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: 0 if success; error code otherwise
 */
int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_clk_ctrl - enable/disable rotator clock with reference counting
 * @mgr: Pointer to rotator manager
 * @enable: true to enable clock; false to disable clock
 * return: 0 if success; error code otherwise
 */
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable);

/*
 * sde_rot_mgr_lock - serialization lock prior to rotator manager calls
 * @mgr: Pointer to rotator manager
 */
static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr)
{
	mutex_lock(&mgr->lock);
}

/*
 * sde_rot_mgr_lock - serialization unlock after rotator manager calls
 * @mgr: Pointer to rotator manager
 */
static inline void sde_rot_mgr_unlock(struct sde_rot_mgr *mgr)
{
	mutex_unlock(&mgr->lock);
+176 −63
Original line number Diff line number Diff line
@@ -413,16 +413,15 @@ static int sde_rotator_start_streaming(struct vb2_queue *q, unsigned int count)
	SDEDEV_DBG(rot_dev->dev, "start streaming s:%d t:%d\n",
			ctx->session_id, q->type);

	if (!IS_ERR_OR_NULL(ctx->request) ||
				atomic_read(&ctx->command_pending))
	if (!list_empty(&ctx->pending_list)) {
		SDEDEV_ERR(rot_dev->dev,
				"command pending error s:%d t:%d p:%d\n",
				ctx->session_id, q->type,
				atomic_read(&ctx->command_pending));
				!list_empty(&ctx->pending_list));
		return -EINVAL;
	}

	ctx->request = NULL;
	ctx->abort_pending = 0;
	atomic_set(&ctx->command_pending, 0);

	return 0;
}
@@ -443,18 +442,18 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q)

	SDEDEV_DBG(rot_dev->dev, "stop streaming s:%d t:%d p:%d\n",
			ctx->session_id, q->type,
			atomic_read(&ctx->command_pending));
			!list_empty(&ctx->pending_list));
	ctx->abort_pending = 1;
	mutex_unlock(q->lock);
	ret = wait_event_timeout(ctx->wait_queue,
			(atomic_read(&ctx->command_pending) == 0),
			list_empty(&ctx->pending_list),
			msecs_to_jiffies(rot_dev->streamoff_timeout));
	mutex_lock(q->lock);
	if (!ret)
		SDEDEV_ERR(rot_dev->dev,
				"timeout to stream off s:%d t:%d p:%d\n",
				ctx->session_id, q->type,
				atomic_read(&ctx->command_pending));
				!list_empty(&ctx->pending_list));

	sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);

@@ -737,9 +736,7 @@ static ssize_t sde_rotator_ctx_show(struct kobject *kobj,
			ctx->format_cap.fmt.pix.bytesperline,
			ctx->format_cap.fmt.pix.sizeimage);
	SPRINT("abort_pending=%d\n", ctx->abort_pending);
	SPRINT("command_pending=%d\n", atomic_read(&ctx->command_pending));
	SPRINT("submit_work=%d\n", work_busy(&ctx->submit_work));
	SPRINT("retire_work=%d\n", work_busy(&ctx->retire_work));
	SPRINT("command_pending=%d\n", !list_empty(&ctx->pending_list));
	SPRINT("sequence=%u\n",
		sde_rotator_get_timeline_commit_ts(ctx->work_queue.timeline));
	SPRINT("timestamp=%u\n",
@@ -858,7 +855,7 @@ static int sde_rotator_open(struct file *file)
	struct sde_rotator_ctx *ctx;
	struct v4l2_ctrl_handler *ctrl_handler;
	char name[32];
	int ret;
	int i, ret;

	if (atomic_read(&rot_dev->mgr->device_suspended))
		return -EPERM;
@@ -883,7 +880,6 @@ static int sde_rotator_open(struct file *file)
	ctx->vflip = 0;
	ctx->rotate = 0;
	ctx->secure = 0;
	atomic_set(&ctx->command_pending, 0);
	ctx->abort_pending = 0;
	ctx->format_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ctx->format_cap.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2;
@@ -898,8 +894,21 @@ static int sde_rotator_open(struct file *file)
	ctx->crop_out.width = 640;
	ctx->crop_out.height = 480;
	init_waitqueue_head(&ctx->wait_queue);
	INIT_WORK(&ctx->submit_work, sde_rotator_submit_handler);
	INIT_WORK(&ctx->retire_work, sde_rotator_retire_handler);
	spin_lock_init(&ctx->list_lock);
	INIT_LIST_HEAD(&ctx->pending_list);
	INIT_LIST_HEAD(&ctx->retired_list);

	for (i = 0 ; i < ARRAY_SIZE(ctx->requests); i++) {
		struct sde_rotator_request *request = &ctx->requests[i];

		INIT_WORK(&request->submit_work,
				sde_rotator_submit_handler);
		INIT_WORK(&request->retire_work,
				sde_rotator_retire_handler);
		request->ctx = ctx;
		INIT_LIST_HEAD(&request->list);
		list_add_tail(&request->list, &ctx->retired_list);
	}

	v4l2_fh_init(&ctx->fh, video);
	file->private_data = &ctx->fh;
@@ -1010,6 +1019,7 @@ static int sde_rotator_release(struct file *file)
	struct sde_rotator_ctx *ctx =
			sde_rotator_ctx_from_fh(file->private_data);
	u32 session_id = ctx->session_id;
	struct list_head *curr, *next;

	ATRACE_END(ctx->kobj.name);

@@ -1020,16 +1030,28 @@ static int sde_rotator_release(struct file *file)
	v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
	v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
	mutex_unlock(&rot_dev->lock);
	SDEDEV_DBG(rot_dev->dev, "release submit work s:%d w:%x\n",
			session_id, work_busy(&ctx->submit_work));
	cancel_work_sync(&ctx->submit_work);
	SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id);
	list_for_each_safe(curr, next, &ctx->pending_list) {
		struct sde_rotator_request *request =
			container_of(curr, struct sde_rotator_request, list);

		SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n",
				session_id);
		cancel_work_sync(&request->submit_work);
	}
	SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id);
	sde_rot_mgr_lock(rot_dev->mgr);
	sde_rotator_session_close(rot_dev->mgr, ctx->private, session_id);
	sde_rot_mgr_unlock(rot_dev->mgr);
	SDEDEV_DBG(rot_dev->dev, "release retire work s:%d w:%x\n",
			session_id, work_busy(&ctx->retire_work));
	cancel_work_sync(&ctx->retire_work);
	SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", session_id);
	list_for_each_safe(curr, next, &ctx->pending_list) {
		struct sde_rotator_request *request =
			container_of(curr, struct sde_rotator_request, list);

		SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n",
				session_id);
		cancel_work_sync(&request->retire_work);
	}
	mutex_lock(&rot_dev->lock);
	SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id);
	sde_rotator_destroy_timeline(ctx->work_queue.timeline);
@@ -1047,6 +1069,61 @@ static int sde_rotator_release(struct file *file)
	return 0;
}

/*
 * sde_rotator_update_retire_sequence - update retired sequence of the context
 *	referenced in the request, and wake up any waiting for update event
 * @request: Pointer to rotator request
 */
static void sde_rotator_update_retire_sequence(
		struct sde_rotator_request *request)
{
	struct sde_rotator_ctx *ctx;
	struct sde_rot_entry_container *req;

	if (!request || !request->ctx) {
		SDEROT_ERR("invalid parameters\n");
		return;
	}

	ctx = request->ctx;
	req = request->req;

	if (req && req->entries && req->count)
		ctx->retired_sequence_id =
				req->entries[req->count - 1].item.sequence_id;

	wake_up(&ctx->wait_queue);

	SDEROT_DBG("update sequence s:%d.%d\n",
				ctx->session_id, ctx->retired_sequence_id);
}

/*
 * sde_rotator_retire_request - retire the given rotator request with
 *	device mutex locked
 * @request: Pointer to rotator request
 */
static void sde_rotator_retire_request(struct sde_rotator_request *request)
{
	struct sde_rotator_ctx *ctx;

	if (!request || !request->ctx) {
		SDEROT_ERR("invalid parameters\n");
		return;
	}

	ctx = request->ctx;

	request->req = NULL;
	spin_lock(&ctx->list_lock);
	list_del_init(&request->list);
	list_add_tail(&request->list, &ctx->retired_list);
	spin_unlock(&ctx->list_lock);

	SDEROT_DBG("retire request s:%d.%d\n",
				ctx->session_id, ctx->retired_sequence_id);
}

/*
 * sde_rotator_poll - rotator device pool method.
 * @file: Pointer to file struct.
@@ -1992,8 +2069,10 @@ static void sde_rotator_retire_handler(struct work_struct *work)
	struct vb2_v4l2_buffer *dst_buf;
	struct sde_rotator_ctx *ctx;
	struct sde_rotator_device *rot_dev;
	struct sde_rotator_request *request;

	ctx = container_of(work, struct sde_rotator_ctx, retire_work);
	request = container_of(work, struct sde_rotator_request, retire_work);
	ctx = request->ctx;

	if (!ctx || !ctx->rot_dev) {
		SDEROT_ERR("null context/device\n");
@@ -2008,15 +2087,14 @@ static void sde_rotator_retire_handler(struct work_struct *work)
	if (ctx->abort_pending) {
		SDEDEV_DBG(rot_dev->dev, "abort command in retire s:%d\n",
				ctx->session_id);
		ctx->request = ERR_PTR(-EINTR);
		atomic_dec(&ctx->command_pending);
		wake_up(&ctx->wait_queue);
		sde_rotator_update_retire_sequence(request);
		sde_rotator_retire_request(request);
		mutex_unlock(&rot_dev->lock);
		return;
	}

	if (rot_dev->early_submit) {
		if (IS_ERR_OR_NULL(ctx->request)) {
		if (IS_ERR_OR_NULL(request->req)) {
			/* fail pending request or something wrong */
			SDEDEV_ERR(rot_dev->dev,
					"pending request fail in retire s:%d\n",
@@ -2037,9 +2115,8 @@ static void sde_rotator_retire_handler(struct work_struct *work)
				src_buf, dst_buf);
		}

		ctx->request = NULL;
		atomic_dec(&ctx->command_pending);
		wake_up(&ctx->wait_queue);
		sde_rotator_update_retire_sequence(request);
		sde_rotator_retire_request(request);
		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
		v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
@@ -2052,9 +2129,11 @@ static void sde_rotator_retire_handler(struct work_struct *work)
 * @ctx: Pointer rotator context.
 * @src_buf: Pointer to Vb2 source buffer.
 * @dst_buf: Pointer to Vb2 destination buffer.
 * @request: Pointer to rotator request
 */
static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
	struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf)
	struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf,
	struct sde_rotator_request *request)
{
	struct sde_rotator_device *rot_dev = ctx->rot_dev;
	struct sde_rotation_item item;
@@ -2173,17 +2252,17 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
	}

	req->retireq = ctx->work_queue.rot_work_queue;
	req->retire_work = &ctx->retire_work;
	req->retire_work = &request->retire_work;

	ret = sde_rotator_handle_request_common(
			rot_dev->mgr, ctx->private, req, &item);
			rot_dev->mgr, ctx->private, req);
	if (ret) {
		SDEDEV_ERR(rot_dev->dev, "fail handle request\n");
		goto error_handle_request;
	}

	sde_rotator_queue_request(rot_dev->mgr, ctx->private, req);
	ctx->request = req;
	request->req = req;

	return 0;
error_handle_request:
@@ -2191,7 +2270,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
error_init_request:
error_fence_wait:
error_null_buffer:
	ctx->request = ERR_PTR(ret);
	request->req = NULL;
	return ret;
}

@@ -2207,11 +2286,13 @@ static void sde_rotator_submit_handler(struct work_struct *work)
	struct sde_rotator_device *rot_dev;
	struct vb2_v4l2_buffer *src_buf;
	struct vb2_v4l2_buffer *dst_buf;
	struct sde_rotator_request *request;
	int ret;

	ctx = container_of(work, struct sde_rotator_ctx, submit_work);
	request = container_of(work, struct sde_rotator_request, submit_work);
	ctx = request->ctx;

	if (!ctx->rot_dev) {
	if (!ctx || !ctx->rot_dev) {
		SDEROT_ERR("null device\n");
		return;
	}
@@ -2223,9 +2304,8 @@ static void sde_rotator_submit_handler(struct work_struct *work)
	if (ctx->abort_pending) {
		SDEDEV_DBG(rot_dev->dev, "abort command in submit s:%d\n",
				ctx->session_id);
		ctx->request = ERR_PTR(-EINTR);
		atomic_dec(&ctx->command_pending);
		wake_up(&ctx->wait_queue);
		sde_rotator_update_retire_sequence(request);
		sde_rotator_retire_request(request);
		mutex_unlock(&rot_dev->lock);
		return;
	}
@@ -2235,7 +2315,7 @@ static void sde_rotator_submit_handler(struct work_struct *work)
	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
	sde_rot_mgr_lock(rot_dev->mgr);
	ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf,
			&dst_buf->vb2_buf);
			&dst_buf->vb2_buf, request);
	sde_rot_mgr_unlock(rot_dev->mgr);
	if (ret) {
		SDEDEV_ERR(rot_dev->dev,
@@ -2258,6 +2338,7 @@ static void sde_rotator_device_run(void *priv)
	struct sde_rotator_device *rot_dev;
	struct vb2_v4l2_buffer *src_buf;
	struct vb2_v4l2_buffer *dst_buf;
	struct sde_rotator_request *request;
	int ret;

	if (!ctx || !ctx->rot_dev) {
@@ -2269,8 +2350,11 @@ static void sde_rotator_device_run(void *priv)
	SDEDEV_DBG(rot_dev->dev, "device run s:%d\n", ctx->session_id);

	if (rot_dev->early_submit) {
		request = list_first_entry_or_null(&ctx->pending_list,
				struct sde_rotator_request, list);

		/* pending request mode, check for completion */
		if (IS_ERR_OR_NULL(ctx->request)) {
		if (!request || IS_ERR_OR_NULL(request->req)) {
			/* pending request fails or something wrong. */
			SDEDEV_ERR(rot_dev->dev,
				"pending request fail in device run s:%d\n",
@@ -2278,19 +2362,19 @@ static void sde_rotator_device_run(void *priv)
			rot_dev->stats.fail_count++;
			ATRACE_INT("fail_count", rot_dev->stats.fail_count);
			goto error_process_buffers;
		} else if (!atomic_read(&ctx->request->pending_count)) {

		} else if (!atomic_read(&request->req->pending_count)) {
			/* pending request completed. signal done. */
			int failed_count =
				atomic_read(&ctx->request->failed_count);
				atomic_read(&request->req->failed_count);
			SDEDEV_DBG(rot_dev->dev,
				"pending request completed in device run s:%d\n",
				ctx->session_id);

			/* disconnect request (will be freed by core layer) */
			sde_rot_mgr_lock(rot_dev->mgr);
			ctx->request->retireq = NULL;
			ctx->request->retire_work = NULL;
			ctx->request = NULL;
			sde_rotator_req_finish(rot_dev->mgr, ctx->private,
					request->req);
			sde_rot_mgr_unlock(rot_dev->mgr);

			if (failed_count) {
@@ -2314,8 +2398,8 @@ static void sde_rotator_device_run(void *priv)
				goto error_process_buffers;
			}

			atomic_dec(&ctx->command_pending);
			wake_up(&ctx->wait_queue);
			sde_rotator_update_retire_sequence(request);
			sde_rotator_retire_request(request);
			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
			v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
			v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
@@ -2327,17 +2411,28 @@ static void sde_rotator_device_run(void *priv)

			/* disconnect request (will be freed by core layer) */
			sde_rot_mgr_lock(rot_dev->mgr);
			ctx->request->retireq = NULL;
			ctx->request->retire_work = NULL;
			ctx->request = ERR_PTR(-EIO);
			sde_rotator_req_finish(rot_dev->mgr, ctx->private,
					request->req);
			sde_rot_mgr_unlock(rot_dev->mgr);

			goto error_process_buffers;
		}
	} else {
		/* no pending request. submit buffer the usual way. */
		atomic_inc(&ctx->command_pending);
		request = list_first_entry_or_null(&ctx->retired_list,
				struct sde_rotator_request, list);
		if (!request) {
			SDEDEV_ERR(rot_dev->dev,
				"no free request in device run s:%d\n",
				ctx->session_id);
			goto error_retired_list;
		}

		spin_lock(&ctx->list_lock);
		list_del_init(&request->list);
		list_add_tail(&request->list, &ctx->pending_list);
		spin_unlock(&ctx->list_lock);

		/* no pending request. submit buffer the usual way. */
		dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
		if (!src_buf || !dst_buf) {
@@ -2350,13 +2445,12 @@ static void sde_rotator_device_run(void *priv)

		sde_rot_mgr_lock(rot_dev->mgr);
		ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf,
				&dst_buf->vb2_buf);
				&dst_buf->vb2_buf, request);
		sde_rot_mgr_unlock(rot_dev->mgr);
		if (ret) {
			SDEDEV_ERR(rot_dev->dev,
				"fail process buffer in device run s:%d\n",
				ctx->session_id);
			ctx->request = ERR_PTR(ret);
			rot_dev->stats.fail_count++;
			ATRACE_INT("fail_count", rot_dev->stats.fail_count);
			goto error_process_buffers;
@@ -2366,8 +2460,9 @@ static void sde_rotator_device_run(void *priv)
	return;
error_process_buffers:
error_empty_buffer:
	atomic_dec(&ctx->command_pending);
	wake_up(&ctx->wait_queue);
error_retired_list:
	sde_rotator_update_retire_sequence(request);
	sde_rotator_retire_request(request);
	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
	if (src_buf)
@@ -2406,6 +2501,7 @@ static int sde_rotator_job_ready(void *priv)
{
	struct sde_rotator_ctx *ctx = priv;
	struct sde_rotator_device *rot_dev;
	struct sde_rotator_request *request;
	int ret = 0;

	if (!ctx || !ctx->rot_dev) {
@@ -2416,26 +2512,43 @@ static int sde_rotator_job_ready(void *priv)
	rot_dev = ctx->rot_dev;
	SDEDEV_DBG(rot_dev->dev, "job ready s:%d\n", ctx->session_id);

	request = list_first_entry_or_null(&ctx->pending_list,
			struct sde_rotator_request, list);

	if (!rot_dev->early_submit) {
		/* always ready in normal mode. */
		ret = 1;
	} else if (IS_ERR(ctx->request)) {
	} else if (request && IS_ERR_OR_NULL(request->req)) {
		/* if pending request fails, forward to device run state. */
		SDEDEV_DBG(rot_dev->dev,
				"pending request fail in job ready s:%d\n",
				ctx->session_id);
		ret = 1;
	} else if (!ctx->request) {
	} else if (list_empty(&ctx->pending_list)) {
		/* if no pending request, submit a new request. */
		SDEDEV_DBG(rot_dev->dev,
				"submit job s:%d sc:%d dc:%d p:%d\n",
				ctx->session_id,
				v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx),
				v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx),
				atomic_read(&ctx->command_pending));
		atomic_inc(&ctx->command_pending);
		queue_work(ctx->work_queue.rot_work_queue, &ctx->submit_work);
	} else if (!atomic_read(&ctx->request->pending_count)) {
				!list_empty(&ctx->pending_list));

		request = list_first_entry_or_null(&ctx->retired_list,
				struct sde_rotator_request, list);
		if (!request) {
			/* should not happen */
			SDEDEV_ERR(rot_dev->dev,
					"no free request in job ready s:%d\n",
					ctx->session_id);
		} else {
			spin_lock(&ctx->list_lock);
			list_del_init(&request->list);
			list_add_tail(&request->list, &ctx->pending_list);
			spin_unlock(&ctx->list_lock);
			queue_work(ctx->work_queue.rot_work_queue,
					&request->submit_work);
		}
	} else if (request && !atomic_read(&request->req->pending_count)) {
		/* if pending request completed, forward to device run state */
		SDEDEV_DBG(rot_dev->dev,
				"pending request completed in job ready s:%d\n",
+32 −9

File changed.

Preview size limit exceeded, changes collapsed.