mhi: core: Lock MHI_M3 state transition

To avoid any race conditions between MHI_M2 state
transition and MHI_M3 state transition lock the
entire MHI_M3 transition using xfer_lock.

CRs-Fixed: 972390
Change-Id: I7c2e1b7b3966dc5fb8bf2f91bce734bbc58c6fd7
Signed-off-by: Tony Truong <truong@codeaurora.org>
Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
This commit is contained in:
Tony Truong 2016-03-28 18:30:44 -07:00 committed by Sujeev Dias
parent ac489269bb
commit 683cb7801e

View file

@ -909,27 +909,31 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt)
case MHI_STATE_M0: case MHI_STATE_M0:
case MHI_STATE_M1: case MHI_STATE_M1:
case MHI_STATE_M2: case MHI_STATE_M2:
write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
mhi_log(MHI_MSG_INFO, mhi_log(MHI_MSG_INFO,
"Triggering wake out of M2\n"); "Triggering wake out of M2\n");
write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
mhi_dev_ctxt->flags.pending_M3 = 1; mhi_dev_ctxt->flags.pending_M3 = 1;
if ((atomic_read(&mhi_dev_ctxt->flags.m2_transition)) == 0) { if ((atomic_read(&mhi_dev_ctxt->flags.m2_transition)) == 0) {
mhi_log(MHI_MSG_INFO, mhi_log(MHI_MSG_INFO,
"M2 transition not set\n"); "M2 transition not set\n");
mhi_assert_device_wake(mhi_dev_ctxt); mhi_assert_device_wake(mhi_dev_ctxt);
} }
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
r = wait_event_interruptible_timeout( if (mhi_dev_ctxt->mhi_state == MHI_STATE_M2) {
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock,
flags);
r = wait_event_interruptible_timeout(
*mhi_dev_ctxt->mhi_ev_wq.m0_event, *mhi_dev_ctxt->mhi_ev_wq.m0_event,
mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || mhi_dev_ctxt->mhi_state == MHI_STATE_M0,
mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
if (0 == r || -ERESTARTSYS == r) { write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
mhi_log(MHI_MSG_CRITICAL, if (0 == r || -ERESTARTSYS == r) {
"MDM failed to come out of M2.\n"); mhi_log(MHI_MSG_CRITICAL,
mhi_dev_ctxt->counters.m2_event_timeouts++; "MDM failed to come out of M2.\n");
r = -EAGAIN; mhi_dev_ctxt->counters.m2_event_timeouts++;
goto exit; r = -EAGAIN;
goto unlock;
}
} }
break; break;
case MHI_STATE_M3: case MHI_STATE_M3:
@ -943,13 +947,15 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt)
r = 0; r = 0;
goto exit; goto exit;
default: default:
write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
mhi_log(MHI_MSG_INFO, mhi_log(MHI_MSG_INFO,
"MHI state %s, link state %d.\n", "MHI state %s, link state %d.\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state),
mhi_dev_ctxt->flags.link_up); mhi_dev_ctxt->flags.link_up);
break; break;
} }
while (atomic_read(&mhi_dev_ctxt->counters.outbound_acks)) {
if (atomic_read(&mhi_dev_ctxt->counters.outbound_acks)) {
mhi_log(MHI_MSG_INFO, mhi_log(MHI_MSG_INFO,
"There are still %d acks pending from device\n", "There are still %d acks pending from device\n",
atomic_read(&mhi_dev_ctxt->counters.outbound_acks)); atomic_read(&mhi_dev_ctxt->counters.outbound_acks));
@ -957,25 +963,23 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt)
__pm_relax(&mhi_dev_ctxt->w_lock); __pm_relax(&mhi_dev_ctxt->w_lock);
abort_m3 = 1; abort_m3 = 1;
r = -EAGAIN; r = -EAGAIN;
goto exit; goto unlock;
} }
if (atomic_read(&mhi_dev_ctxt->flags.data_pending)) { if (atomic_read(&mhi_dev_ctxt->flags.data_pending)) {
abort_m3 = 1; abort_m3 = 1;
r = -EAGAIN; r = -EAGAIN;
goto exit; goto unlock;
} }
write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
if (mhi_dev_ctxt->flags.pending_M0) { if (mhi_dev_ctxt->flags.pending_M0) {
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
r = -EAGAIN; r = -EAGAIN;
goto exit; goto unlock;
} }
mhi_dev_ctxt->flags.pending_M3 = 1; mhi_dev_ctxt->flags.pending_M3 = 1;
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3); mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3);
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
mhi_log(MHI_MSG_INFO, mhi_log(MHI_MSG_INFO,
"Waiting for M3 completion.\n"); "Waiting for M3 completion.\n");
r = wait_event_interruptible_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event, r = wait_event_interruptible_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event,
@ -998,16 +1002,20 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt)
r = mhi_set_bus_request(mhi_dev_ctxt, 0); r = mhi_set_bus_request(mhi_dev_ctxt, 0);
if (r) if (r)
mhi_log(MHI_MSG_INFO, "Failed to set bus freq ret %d\n", r); mhi_log(MHI_MSG_INFO, "Failed to set bus freq ret %d\n", r);
exit: goto exit;
unlock:
mhi_dev_ctxt->flags.pending_M3 = 0;
if (abort_m3) { if (abort_m3) {
write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
atomic_inc(&mhi_dev_ctxt->flags.data_pending); atomic_inc(&mhi_dev_ctxt->flags.data_pending);
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
ring_all_chan_dbs(mhi_dev_ctxt); ring_all_chan_dbs(mhi_dev_ctxt);
ring_all_cmd_dbs(mhi_dev_ctxt); ring_all_cmd_dbs(mhi_dev_ctxt);
atomic_dec(&mhi_dev_ctxt->flags.data_pending); atomic_dec(&mhi_dev_ctxt->flags.data_pending);
mhi_deassert_device_wake(mhi_dev_ctxt); mhi_deassert_device_wake(mhi_dev_ctxt);
} else {
write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
} }
exit:
mhi_dev_ctxt->flags.pending_M3 = 0; mhi_dev_ctxt->flags.pending_M3 = 0;
mutex_unlock(&mhi_dev_ctxt->pm_lock); mutex_unlock(&mhi_dev_ctxt->pm_lock);
return r; return r;