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: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
Hemant Kumar 2019-12-13 14:34:14 -08:00 • committed by Gerrit - the friendly Code Review server
commit ad557197eb
5 changed files with 23 additions and 16 deletions

View file

@ -592,7 +592,6 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
return -ENOMEM;
spin_lock_init(&mhi_tsync->lock);
mutex_init(&mhi_tsync->lpm_mutex);
INIT_LIST_HEAD(&mhi_tsync->head);
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);
mutex_init(&mhi_cntrl->pm_mutex);
mutex_init(&mhi_cntrl->tsync_mutex);
rwlock_init(&mhi_cntrl->pm_lock);
spin_lock_init(&mhi_cntrl->transition_lock);
spin_lock_init(&mhi_cntrl->wlock);

View file

@ -714,7 +714,6 @@ struct mhi_timesync {
enum MHI_EV_CCS ccs;
struct completion completion;
spinlock_t lock; /* list protection */
struct mutex lpm_mutex; /* lpm protection */
struct list_head head;
};

View file

@ -759,10 +759,12 @@ static const struct attribute_group mhi_tsync_group = {
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl)
{
if (mhi_cntrl->mhi_tsync) {
mutex_lock(&mhi_cntrl->tsync_mutex);
sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj,
&mhi_tsync_group);
kfree(mhi_cntrl->mhi_tsync);
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;
int ret;
mutex_lock(&mhi_cntrl->tsync_mutex);
/* not all devices support time feature */
if (!mhi_tsync)
return -EIO;
if (!mhi_tsync) {
ret = -EIO;
goto err_unlock;
}
/* bring to M0 state */
ret = __mhi_device_get_sync(mhi_cntrl);
if (ret)
return ret;
mutex_lock(&mhi_tsync->lpm_mutex);
goto err_unlock;
read_lock_bh(&mhi_cntrl->pm_lock);
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:
mhi_cntrl->wake_put(mhi_cntrl, false);
read_unlock_bh(&mhi_cntrl->pm_lock);
mutex_unlock(&mhi_tsync->lpm_mutex);
err_unlock:
mutex_unlock(&mhi_cntrl->tsync_mutex);
return ret;
}
EXPORT_SYMBOL(mhi_get_remote_time_sync);
@ -2418,13 +2421,16 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev,
int ret;
/* not all devices support time feature */
if (!mhi_tsync)
return -EIO;
mutex_lock(&mhi_cntrl->tsync_mutex);
if (!mhi_tsync) {
ret = -EIO;
goto err_unlock;
}
/* tsync db can only be rung in M0 state */
ret = __mhi_device_get_sync(mhi_cntrl);
if (ret)
return ret;
goto err_unlock;
/*
* technically we can use GFP_KERNEL, but wants to avoid
@ -2483,7 +2489,8 @@ error_no_mem:
read_lock_bh(&mhi_cntrl->pm_lock);
mhi_cntrl->wake_put(mhi_cntrl, false);
read_unlock_bh(&mhi_cntrl->pm_lock);
err_unlock:
mutex_unlock(&mhi_cntrl->tsync_mutex);
return ret;
}
EXPORT_SYMBOL(mhi_get_remote_time);

View file

@ -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->low_priority_worker);
/* remove support for time sync */
mhi_destroy_timesync(mhi_cntrl);
mutex_lock(&mhi_cntrl->pm_mutex);
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;
}
/* remove support for time sync */
mhi_destroy_timesync(mhi_cntrl);
if (cur_state == MHI_PM_SYS_ERR_PROCESS) {
mhi_ready_state_transition(mhi_cntrl);
} else {

View file

@ -303,6 +303,7 @@ struct mhi_controller {
/* caller should grab pm_mutex for suspend/resume operations */
struct mutex pm_mutex;
struct mutex tsync_mutex;
bool pre_init;
rwlock_t pm_lock;
u32 pm_state;