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

Commit ad557197 authored by Hemant Kumar's avatar Hemant Kumar Committed by Gerrit - the friendly Code Review server
Browse files

mhi: core: Synchronize time sync operation and removal



If time sync is requested by user space when endpoint is shutting
down dev_wake count gets incremented. This is causing assert when
shutdown API checks the dev_wake count and it is still non-zero.
Fix this issue by protecting time sync API and removal of time sync
under tsync_mutex. This helps to take care of a race condition when
time sync is requested while time sync remove in progress and also
makes sure that dev_wake count becomes zero when time sync remove
is done to prevent assert condition.

Change-Id: I4e758611613e541537dd900306aa81dd3b4a9f3a
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent 96cd1812
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -592,7 +592,6 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
		return -ENOMEM;
		return -ENOMEM;


	spin_lock_init(&mhi_tsync->lock);
	spin_lock_init(&mhi_tsync->lock);
	mutex_init(&mhi_tsync->lpm_mutex);
	INIT_LIST_HEAD(&mhi_tsync->head);
	INIT_LIST_HEAD(&mhi_tsync->head);
	init_completion(&mhi_tsync->completion);
	init_completion(&mhi_tsync->completion);


@@ -1356,6 +1355,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)


	INIT_LIST_HEAD(&mhi_cntrl->transition_list);
	INIT_LIST_HEAD(&mhi_cntrl->transition_list);
	mutex_init(&mhi_cntrl->pm_mutex);
	mutex_init(&mhi_cntrl->pm_mutex);
	mutex_init(&mhi_cntrl->tsync_mutex);
	rwlock_init(&mhi_cntrl->pm_lock);
	rwlock_init(&mhi_cntrl->pm_lock);
	spin_lock_init(&mhi_cntrl->transition_lock);
	spin_lock_init(&mhi_cntrl->transition_lock);
	spin_lock_init(&mhi_cntrl->wlock);
	spin_lock_init(&mhi_cntrl->wlock);
+0 −1
Original line number Original line Diff line number Diff line
@@ -714,7 +714,6 @@ struct mhi_timesync {
	enum MHI_EV_CCS ccs;
	enum MHI_EV_CCS ccs;
	struct completion completion;
	struct completion completion;
	spinlock_t lock; /* list protection */
	spinlock_t lock; /* list protection */
	struct mutex lpm_mutex; /* lpm protection */
	struct list_head head;
	struct list_head head;
};
};


+18 −11
Original line number Original line Diff line number Diff line
@@ -759,10 +759,12 @@ static const struct attribute_group mhi_tsync_group = {
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl)
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl)
{
{
	if (mhi_cntrl->mhi_tsync) {
	if (mhi_cntrl->mhi_tsync) {
		mutex_lock(&mhi_cntrl->tsync_mutex);
		sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj,
		sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj,
				   &mhi_tsync_group);
				   &mhi_tsync_group);
		kfree(mhi_cntrl->mhi_tsync);
		kfree(mhi_cntrl->mhi_tsync);
		mhi_cntrl->mhi_tsync = NULL;
		mhi_cntrl->mhi_tsync = NULL;
		mutex_unlock(&mhi_cntrl->tsync_mutex);
	}
	}
}
}


@@ -2346,16 +2348,17 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev,
	struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
	struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync;
	int ret;
	int ret;


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


	/* bring to M0 state */
	/* bring to M0 state */
	ret = __mhi_device_get_sync(mhi_cntrl);
	ret = __mhi_device_get_sync(mhi_cntrl);
	if (ret)
	if (ret)
		return ret;
		goto err_unlock;

	mutex_lock(&mhi_tsync->lpm_mutex);


	read_lock_bh(&mhi_cntrl->pm_lock);
	read_lock_bh(&mhi_cntrl->pm_lock);
	if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
	if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
@@ -2389,8 +2392,8 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev,
error_invalid_state:
error_invalid_state:
	mhi_cntrl->wake_put(mhi_cntrl, false);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	read_unlock_bh(&mhi_cntrl->pm_lock);
	read_unlock_bh(&mhi_cntrl->pm_lock);
	mutex_unlock(&mhi_tsync->lpm_mutex);
err_unlock:

	mutex_unlock(&mhi_cntrl->tsync_mutex);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL(mhi_get_remote_time_sync);
EXPORT_SYMBOL(mhi_get_remote_time_sync);
@@ -2418,13 +2421,16 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	int ret;
	int ret;


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


	/* tsync db can only be rung in M0 state */
	/* tsync db can only be rung in M0 state */
	ret = __mhi_device_get_sync(mhi_cntrl);
	ret = __mhi_device_get_sync(mhi_cntrl);
	if (ret)
	if (ret)
		return ret;
		goto err_unlock;


	/*
	/*
	 * technically we can use GFP_KERNEL, but wants to avoid
	 * technically we can use GFP_KERNEL, but wants to avoid
@@ -2483,7 +2489,8 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
	read_lock_bh(&mhi_cntrl->pm_lock);
	read_lock_bh(&mhi_cntrl->pm_lock);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	read_unlock_bh(&mhi_cntrl->pm_lock);
	read_unlock_bh(&mhi_cntrl->pm_lock);

err_unlock:
	mutex_unlock(&mhi_cntrl->tsync_mutex);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL(mhi_get_remote_time);
EXPORT_SYMBOL(mhi_get_remote_time);
+3 −3
Original line number Original line Diff line number Diff line
@@ -635,6 +635,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
	flush_work(&mhi_cntrl->fw_worker);
	flush_work(&mhi_cntrl->fw_worker);
	flush_work(&mhi_cntrl->low_priority_worker);
	flush_work(&mhi_cntrl->low_priority_worker);


	/* remove support for time sync */
	mhi_destroy_timesync(mhi_cntrl);

	mutex_lock(&mhi_cntrl->pm_mutex);
	mutex_lock(&mhi_cntrl->pm_mutex);


	MHI_ASSERT(atomic_read(&mhi_cntrl->dev_wake), "dev_wake != 0");
	MHI_ASSERT(atomic_read(&mhi_cntrl->dev_wake), "dev_wake != 0");
@@ -669,9 +672,6 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
		er_ctxt->wp = er_ctxt->rbase;
		er_ctxt->wp = er_ctxt->rbase;
	}
	}


	/* remove support for time sync */
	mhi_destroy_timesync(mhi_cntrl);

	if (cur_state == MHI_PM_SYS_ERR_PROCESS) {
	if (cur_state == MHI_PM_SYS_ERR_PROCESS) {
		mhi_ready_state_transition(mhi_cntrl);
		mhi_ready_state_transition(mhi_cntrl);
	} else {
	} else {
+1 −0
Original line number Original line Diff line number Diff line
@@ -303,6 +303,7 @@ struct mhi_controller {


	/* caller should grab pm_mutex for suspend/resume operations */
	/* caller should grab pm_mutex for suspend/resume operations */
	struct mutex pm_mutex;
	struct mutex pm_mutex;
	struct mutex tsync_mutex;
	bool pre_init;
	bool pre_init;
	rwlock_t pm_lock;
	rwlock_t pm_lock;
	u32 pm_state;
	u32 pm_state;