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

Commit 3ce07c04 authored by Clarence Ip's avatar Clarence Ip
Browse files

msm: sde: avoid commit kickoff if no inline start



Avoid triggering the rotator kickoff unless the 'start'
notification has been received for inline rotation use
cases. This prevents the rotator hardware from waiting
for, and timing out on, a hardware start event that
never triggers due to the DRM driver aborting the commit
cycle.

Change-Id: If11268795280ca6f7de331fe942e7eb4f5fdc2eb
Signed-off-by: default avatarClarence Ip <cip@codeaurora.org>
parent 310e9b0f
Loading
Loading
Loading
Loading
+109 −45
Original line number Diff line number Diff line
@@ -913,6 +913,44 @@ static int sde_rotator_is_hw_available(struct sde_rot_mgr *mgr,
	}
}

/*
 * sde_rotator_req_wait_for_idle - wait for hw for a request to be idle
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 */
static void sde_rotator_req_wait_for_idle(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req)
{
	struct sde_rot_queue *queue;
	struct sde_rot_hw_resource *hw;
	int i, ret;

	if (!mgr || !req) {
		SDEROT_ERR("invalid params\n");
		return;
	}

	for (i = 0; i < req->count; i++) {
		queue = req->entries[i].commitq;
		if (!queue || !queue->hw)
			continue;
		hw = queue->hw;
		while (atomic_read(&hw->num_active) > 1) {
			sde_rot_mgr_unlock(mgr);
			ret = wait_event_timeout(hw->wait_queue,
				atomic_read(&hw->num_active) <= 1,
				msecs_to_jiffies(mgr->hwacquire_timeout));
			sde_rot_mgr_lock(mgr);
			if (!ret) {
				SDEROT_ERR(
					"timeout waiting for hw idle, a:%d\n",
					atomic_read(&hw->num_active));
				return;
			}
		}
	}
}

/*
 * sde_rotator_get_hw_resource - block waiting for hw availability or timeout
 * @queue: Pointer to rotator queue
@@ -1219,6 +1257,11 @@ void sde_rotator_queue_request(struct sde_rot_mgr *mgr,
		return;
	}

	if (!req->entries) {
		SDEROT_DBG("no entries in request\n");
		return;
	}

	for (i = 0; i < req->count; i++) {
		entry = req->entries + i;
		queue = entry->commitq;
@@ -1541,10 +1584,23 @@ static void sde_rotator_commit_handler(struct kthread_work *work)
		goto error;
	}

	if (entry->item.ts)
		entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();

	ret = sde_rotator_req_wait_start(mgr, request);
	if (ret) {
		SDEROT_WARN("timeout waiting for inline start\n");
		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
				SDE_ROT_EVTLOG_ERROR);
		goto kickoff_error;
	}

	ret = mgr->ops_kickoff_entry(hw, entry);
	if (ret) {
		SDEROT_ERR("fail to do kickoff %d\n", ret);
		goto error;
		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
				SDE_ROT_EVTLOG_ERROR);
		goto kickoff_error;
	}

	if (entry->item.ts)
@@ -1555,6 +1611,13 @@ static void sde_rotator_commit_handler(struct kthread_work *work)
	kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work);
	sde_rot_mgr_unlock(mgr);
	return;
kickoff_error:
	/*
	 * Wait for any pending operations to complete before cancelling this
	 * one so that the system is left in a consistent state.
	 */
	sde_rotator_req_wait_for_idle(mgr, request);
	mgr->ops_cancel_hw(hw, entry);
error:
	sde_smmu_ctrl(0);
smmu_error:
@@ -1608,18 +1671,6 @@ static void sde_rotator_done_handler(struct kthread_work *work)
		entry->item.flags,
		entry->dnsc_factor_w, entry->dnsc_factor_h);

	ret = wait_for_completion_timeout(
			&entry->item.inline_start,
			msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
	if (!ret) {
		SDEROT_WARN("timeout waiting for inline start\n");
		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
				SDE_ROT_EVTLOG_ERROR);
	}

	if (entry->item.ts)
		entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();

	SDEROT_EVTLOG(entry->item.session_id, 0);
	ret = mgr->ops_wait_for_entry(hw, entry);
	if (ret) {
@@ -2155,34 +2206,6 @@ int sde_rotator_validate_request(struct sde_rot_mgr *mgr,
	return ret;
}

/*
 * sde_rotator_commit_request - commit the request to hardware
 * @mgr: pointer to rotator manager
 * @private: pointer to per file context
 * @req: pointer to rotation request
 *
 * This differs from sde_rotator_queue_request in that this
 * function will wait until request is committed to hardware.
 */
void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req)
{
	int i;

	if (!mgr || !ctx || !req || !req->entries) {
		SDEROT_ERR("null parameters\n");
		return;
	}

	sde_rotator_queue_request(mgr, ctx, req);

	sde_rot_mgr_unlock(mgr);
	for (i = 0; i < req->count; i++)
		kthread_flush_work(&req->entries[i].commit_work);
	sde_rot_mgr_lock(mgr);
}

static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private, u32 session_id)
{
@@ -2399,26 +2422,67 @@ struct sde_rot_entry_container *sde_rotator_req_init(
	return req;
}

void sde_rotator_req_reset_start(struct sde_rot_entry_container *req)
void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req)
{
	int i;

	if (!req)
	if (!mgr || !req)
		return;

	for (i = 0; i < req->count; i++)
		reinit_completion(&req->entries[i].item.inline_start);
}

void sde_rotator_req_set_start(struct sde_rot_entry_container *req)
void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req)
{
	struct kthread_work *commit_work;
	int i;

	if (!req)
	if (!mgr || !req || !req->entries)
		return;

	/* signal ready to start */
	for (i = 0; i < req->count; i++)
		complete_all(&req->entries[i].item.inline_start);

	for (i = 0; i < req->count; i++) {
		commit_work = &req->entries[i].commit_work;

		SDEROT_EVTLOG(i, req->count);

		sde_rot_mgr_unlock(mgr);
		kthread_flush_work(commit_work);
		sde_rot_mgr_lock(mgr);
	}
}

int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req)
{
	struct completion *inline_start;
	int i, ret;

	if (!mgr || !req || !req->entries)
		return -EINVAL;

	/* only wait for sbuf mode */
	if (!mgr->sbuf_ctx || !req->count ||
			mgr->sbuf_ctx != req->entries[0].private)
		return 0;

	for (i = 0; i < req->count; i++) {
		inline_start = &req->entries[i].item.inline_start;

		sde_rot_mgr_unlock(mgr);
		ret = wait_for_completion_timeout(inline_start,
			msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
		sde_rot_mgr_lock(mgr);
	}

	/* wait call returns zero on timeout */
	return ret ? 0 : -EBUSY;
}

void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
+19 −16
Original line number Diff line number Diff line
@@ -115,8 +115,8 @@ enum sde_rotator_ts {
	SDE_ROTATOR_TS_FENCE,		/* wait for source buffer fence */
	SDE_ROTATOR_TS_QUEUE,		/* wait for h/w resource */
	SDE_ROTATOR_TS_COMMIT,		/* prepare h/w command */
	SDE_ROTATOR_TS_START,		/* wait for h/w kickoff rdy (inline) */
	SDE_ROTATOR_TS_FLUSH,		/* initiate h/w processing */
	SDE_ROTATOR_TS_START,		/* h/w triggered (if inline) */
	SDE_ROTATOR_TS_DONE,		/* receive h/w completion */
	SDE_ROTATOR_TS_RETIRE,		/* signal destination buffer fence */
	SDE_ROTATOR_TS_SRCDQB,		/* dequeue source buffer */
@@ -442,6 +442,8 @@ struct sde_rot_mgr {

	int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_cancel_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_wait_for_entry)(struct sde_rot_hw_resource *hw,
@@ -616,20 +618,33 @@ struct sde_rot_entry_container *sde_rotator_req_init(
 *	indicator that allows the rotator to delay its rotator
 *	timeout waiting until such time as the inline rotation has
 *	really started.
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 */
void sde_rotator_req_reset_start(struct sde_rot_entry_container *req);
void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_req_set_start - set inline h/w 'start' indicator
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 */
void sde_rotator_req_set_start(struct sde_rot_entry_container *req);
void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_req_wait_start - wait for inline h/w 'start' indicator
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 * return: Zero on success
 */
int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * 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
 * @mgr: Pointer to rotator manager
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: none
@@ -661,18 +676,6 @@ void sde_rotator_queue_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_commit_request - queue/schedule the given request and wait
 *	until 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_commit_request(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_verify_config_all - verify given rotation configuration
 * @rot_dev: Pointer to rotator device
+5 −5
Original line number Diff line number Diff line
@@ -793,7 +793,7 @@ static int sde_rotator_stat_show(struct seq_file *s, void *data)
					start_time));

		seq_printf(s,
			"s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld st:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
			"s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld st:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
			i,
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
					ts[SDE_ROTATOR_TS_SRCQB])),
@@ -803,12 +803,12 @@ static int sde_rotator_stat_show(struct seq_file *s, void *data)
					ts[SDE_ROTATOR_TS_FENCE])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_COMMIT],
					ts[SDE_ROTATOR_TS_QUEUE])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
					ts[SDE_ROTATOR_TS_COMMIT])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_START],
					ts[SDE_ROTATOR_TS_FLUSH])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
					ts[SDE_ROTATOR_TS_COMMIT])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
					ts[SDE_ROTATOR_TS_START])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
					ts[SDE_ROTATOR_TS_FLUSH])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
					ts[SDE_ROTATOR_TS_DONE])),
			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_SRCDQB],
+3 −3
Original line number Diff line number Diff line
@@ -1685,9 +1685,9 @@ int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
			goto error_handle_request;
		}

		sde_rotator_req_reset_start(req);
		sde_rotator_req_reset_start(rot_dev->mgr, req);

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

		request->committed = true;

@@ -1702,7 +1702,7 @@ int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
		}

		request = cmd->priv_handle;
		sde_rotator_req_set_start(request->req);
		sde_rotator_req_set_start(rot_dev->mgr, request->req);
	} else if (cmd_type == SDE_ROTATOR_INLINE_CMD_CLEANUP) {
		if (!cmd->priv_handle) {
			ret = -EINVAL;
+7 −0
Original line number Diff line number Diff line
@@ -343,6 +343,12 @@ static int sde_rotator_config_hw(struct sde_rot_hw_resource *hw,
	return ret;
}

static int sde_rotator_cancel_hw(struct sde_rot_hw_resource *hw,
	struct sde_rot_entry *entry)
{
	return 0;
}

static int sde_rotator_kickoff_entry(struct sde_rot_hw_resource *hw,
	struct sde_rot_entry *entry)
{
@@ -682,6 +688,7 @@ int sde_rotator_r1_init(struct sde_rot_mgr *mgr)

	mgr->hw_data = hw_data;
	mgr->ops_config_hw = sde_rotator_config_hw;
	mgr->ops_cancel_hw = sde_rotator_cancel_hw;
	mgr->ops_kickoff_entry = sde_rotator_kickoff_entry;
	mgr->ops_wait_for_entry = sde_rotator_wait_for_entry;
	mgr->ops_hw_alloc = sde_rotator_hw_alloc_ext;
Loading