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

Commit 8e1d06fc authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: core: block unbind from userspace till channel reset"

parents c77acc02 d716b115
Loading
Loading
Loading
Loading
+39 −8
Original line number Diff line number Diff line
@@ -1940,7 +1940,8 @@ static int mhi_driver_remove(struct device *dev)
		MHI_CH_STATE_DISABLED,
		MHI_CH_STATE_DISABLED
	};
	int dir;
	int dir, ret;
	bool interrupted = false;

	/* control device has no work to do */
	if (mhi_dev->dev_type == MHI_CONTROLLER_TYPE)
@@ -1948,11 +1949,11 @@ static int mhi_driver_remove(struct device *dev)

	MHI_LOG("Removing device for chan:%s\n", mhi_dev->chan_name);

	/* reset both channels */
	/* move both channels to suspended state and disallow processing */
	for (dir = 0; dir < 2; dir++) {
		mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;

		if (!mhi_chan)
		if (!mhi_chan || mhi_chan->offload_ch)
			continue;

		/* wake all threads waiting for completion */
@@ -1961,15 +1962,45 @@ static int mhi_driver_remove(struct device *dev)
		complete_all(&mhi_chan->completion);
		write_unlock_irq(&mhi_chan->lock);

		/* move channel state to disable, no more processing */
		mutex_lock(&mhi_chan->mutex);
		write_lock_irq(&mhi_chan->lock);
		if (mhi_chan->ch_state != MHI_CH_STATE_DISABLED) {
			ch_state[dir] = mhi_chan->ch_state;
			mhi_chan->ch_state = MHI_CH_STATE_SUSPENDED;
		}
		write_unlock_irq(&mhi_chan->lock);
		mutex_unlock(&mhi_chan->mutex);
	}

	/* wait for each channel to close and reset both channels */
	for (dir = 0; dir < 2; dir++) {
		mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;

		if (!mhi_chan || mhi_chan->offload_ch)
			continue;

		/* unbind request from userspace, wait for channel reset */
		if (!(mhi_cntrl->power_down ||
		    MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) &&
		    ch_state[dir] != MHI_CH_STATE_DISABLED && !interrupted) {
			MHI_ERR("Channel %s busy, wait for it to be reset\n",
				mhi_dev->chan_name);
			ret = wait_event_interruptible(mhi_cntrl->state_event,
				mhi_chan->ch_state == MHI_CH_STATE_DISABLED ||
				MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state));
			if (unlikely(ret))
				interrupted = true;
		}

		/* update channel state as an error can exit above wait */
		mutex_lock(&mhi_chan->mutex);

		write_lock_irq(&mhi_chan->lock);
		ch_state[dir] = mhi_chan->ch_state;
		write_unlock_irq(&mhi_chan->lock);

		/* reset the channel */
		if (!mhi_chan->offload_ch)
		/* reset channel if it was left enabled */
		if (ch_state[dir] != MHI_CH_STATE_DISABLED)
			mhi_reset_chan(mhi_cntrl, mhi_chan);

		mutex_unlock(&mhi_chan->mutex);
@@ -1987,7 +2018,7 @@ static int mhi_driver_remove(struct device *dev)

		mutex_lock(&mhi_chan->mutex);

		if (ch_state[dir] == MHI_CH_STATE_ENABLED &&
		if (ch_state[dir] != MHI_CH_STATE_DISABLED &&
		    !mhi_chan->offload_ch)
			mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);

+11 −3
Original line number Diff line number Diff line
@@ -2055,19 +2055,22 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl,
{
	int ret;
	bool in_mission_mode = false;
	bool notify = false;

	MHI_LOG("Entered: unprepare channel:%d\n", mhi_chan->chan);

	/* no more processing events for this channel */
	mutex_lock(&mhi_chan->mutex);
	write_lock_irq(&mhi_chan->lock);
	if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) {
	if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED &&
	    mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) {
		MHI_LOG("chan:%d is already disabled\n", mhi_chan->chan);
		write_unlock_irq(&mhi_chan->lock);
		mutex_unlock(&mhi_chan->mutex);
		return;
	}

	if (mhi_chan->ch_state == MHI_CH_STATE_SUSPENDED)
		notify = true;
	mhi_chan->ch_state = MHI_CH_STATE_DISABLED;
	write_unlock_irq(&mhi_chan->lock);

@@ -2108,6 +2111,10 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl,
	if (!mhi_chan->offload_ch) {
		mhi_reset_chan(mhi_cntrl, mhi_chan);
		mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);

		/* notify waiters to proceed with unbinding channel */
		if (notify)
			wake_up_all(&mhi_cntrl->state_event);
	}
	MHI_LOG("chan:%d successfully resetted\n", mhi_chan->chan);
	mutex_unlock(&mhi_chan->mutex);
@@ -2382,7 +2389,8 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
		 mhi_chan->chan, cmd == MHI_CMD_START_CHAN ? "START" : "STOP");

	/* if channel is not active state state do not allow to state change */
	if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) {
	if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED &&
	    mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) {
		ret = -EINVAL;
		MHI_LOG("channel:%d is not in active state, ch_state%d\n",
			mhi_chan->chan, mhi_chan->ch_state);