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

Commit 798e407b authored by Bhaumik Bhatt's avatar Bhaumik Bhatt
Browse files

mhi: core: Enable both time synchronization methods to co-exist



Due to co-existence of both time synchronization methods on a
platform, it is likely that a doorbell method response can be pending
while another host client requests for time using the MMIO or
synchronous method. Wait for completion of the doorbell method and
return the local and remote times from that request as the device may
not be able to handle both requests or host is likely to end up reading
corrupted time values. Also, ensure the doorbell method request is done
while holding the bus vote so the host stays awake and receives the
response as soon as possible.

Change-Id: If876905eb523fd65f3758f13b75c035de4108d8d
Signed-off-by: default avatarBhaumik Bhatt <bbhatt@codeaurora.org>
parent 820d9a40
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -346,6 +346,9 @@ void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl)
		}
		spin_unlock(&mhi_tsync->lock);

		if (mhi_tsync->db_response_pending)
			complete(&mhi_tsync->db_completion);

		kfree(mhi_cntrl->mhi_tsync);
		mhi_cntrl->mhi_tsync = NULL;
		mutex_unlock(&mhi_cntrl->tsync_mutex);
+2 −0
Original line number Diff line number Diff line
@@ -727,8 +727,10 @@ struct mhi_timesync {
	void __iomem *time_reg;
	u32 int_sequence;
	u64 local_time;
	u64 remote_time;
	bool db_support;
	bool db_response_pending;
	struct completion db_completion;
	spinlock_t lock; /* list protection */
	struct list_head head;
};
+48 −16
Original line number Diff line number Diff line
@@ -1402,6 +1402,10 @@ int mhi_process_tsync_ev_ring(struct mhi_controller *mhi_cntrl,
	if (unlikely(mhi_tsync->int_sequence != sequence)) {
		MHI_ASSERT(1, "Unexpected response:0x%llx Expected:0x%llx\n",
			   sequence, mhi_tsync->int_sequence);

		mhi_device_put(mhi_cntrl->mhi_dev,
			       MHI_VOTE_DEVICE | MHI_VOTE_BUS);

		mutex_unlock(&mhi_cntrl->tsync_mutex);
		goto exit_tsync_process;
	}
@@ -1427,6 +1431,11 @@ int mhi_process_tsync_ev_ring(struct mhi_controller *mhi_cntrl,
	} while (true);

	mhi_tsync->db_response_pending = false;
	mhi_tsync->remote_time = remote_time;
	complete(&mhi_tsync->db_completion);

	mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS);

	mutex_unlock(&mhi_cntrl->tsync_mutex);

exit_tsync_process:
@@ -2498,13 +2507,37 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev,
{
	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
	struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
	u64 local_time;
	int ret;

	mutex_lock(&mhi_cntrl->tsync_mutex);
	/* not all devices support time features */
	if (!mhi_tsync) {
		ret = -EIO;
		goto error_unlock;
	if (!mhi_tsync)
		return -EINVAL;

	if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
		MHI_ERR("MHI is not in active state, pm_state:%s\n",
			to_mhi_pm_state_str(mhi_cntrl->pm_state));
		return -EIO;
	}

	mutex_lock(&mhi_cntrl->tsync_mutex);

	/* return times from last async request completion */
	if (mhi_tsync->db_response_pending) {
		local_time = mhi_tsync->local_time;
		mutex_unlock(&mhi_cntrl->tsync_mutex);

		ret = wait_for_completion_timeout(&mhi_tsync->db_completion,
				       msecs_to_jiffies(mhi_cntrl->timeout_ms));
		if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || !ret) {
			MHI_ERR("Pending DB request did not complete, abort\n");
			return -EAGAIN;
		}

		*t_host = local_time;
		*t_dev = mhi_tsync->remote_time;

		return 0;
	}

	/* bring to M0 state */
@@ -2577,14 +2610,13 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	int ret = 0;

	/* not all devices support all time features */
	if (!mhi_tsync || !mhi_tsync->db_support)
		return -EINVAL;

	mutex_lock(&mhi_cntrl->tsync_mutex);
	if (!mhi_tsync || !mhi_tsync->db_support) {
		ret = -EIO;
		goto error_unlock;
	}

	/* tsync db can only be rung in M0 state */
	ret = __mhi_device_get_sync(mhi_cntrl);
	ret = mhi_device_get_sync(mhi_cntrl->mhi_dev,
				  MHI_VOTE_DEVICE | MHI_VOTE_BUS);
	if (ret)
		goto error_unlock;

@@ -2652,21 +2684,21 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	MHI_VERB("time DB request with seq:0x%llx\n", mhi_tsync->int_sequence);

	mhi_tsync->db_response_pending = true;
	init_completion(&mhi_tsync->db_completion);

skip_tsync_db:
	spin_lock(&mhi_tsync->lock);
	list_add_tail(&tsync_node->node, &mhi_tsync->head);
	spin_unlock(&mhi_tsync->lock);

	ret = 0;
	mutex_unlock(&mhi_cntrl->tsync_mutex);

	return 0;

error_invalid_state:
	if (ret)
	kfree(tsync_node);
error_no_mem:
	read_lock_bh(&mhi_cntrl->pm_lock);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	read_unlock_bh(&mhi_cntrl->pm_lock);
	mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS);
error_unlock:
	mutex_unlock(&mhi_cntrl->tsync_mutex);
	return ret;