mhi: core: improve bandwidth switch events processing

We may unnecessarily wake up the device when there is no pending
bandwidth switch request. Avoid that by only asserting device wake if
one is pending. We can also have the underlying MHI bus go to suspend
while a device requested bandwidth switch is yet to be processed.
Prevent host suspends by capturing both bus and device votes and
increment pending packets to reject suspends while the processing is
ongoing.

Change-Id: I4eddb6bf9eaa973be5c0b0ac516269e54599b9f2
Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org>
This commit is contained in:
Bhaumik Bhatt 2020-04-03 14:13:12 -07:00
commit 649971df7a

View file

@ -1437,29 +1437,12 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
struct mhi_link_info link_info, *cur_info = &mhi_cntrl->mhi_link_info;
int result, ret = 0;
if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) {
MHI_LOG("No EV access, PM_STATE:%s\n",
to_mhi_pm_state_str(mhi_cntrl->pm_state));
ret = -EIO;
goto exit_no_lock;
}
ret = __mhi_device_get_sync(mhi_cntrl);
if (ret)
goto exit_no_lock;
mutex_lock(&mhi_cntrl->pm_mutex);
spin_lock_bh(&mhi_event->lock);
dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp);
if (ev_ring->rp == dev_rp) {
spin_unlock_bh(&mhi_event->lock);
read_lock_bh(&mhi_cntrl->pm_lock);
mhi_cntrl->wake_put(mhi_cntrl, false);
read_unlock_bh(&mhi_cntrl->pm_lock);
MHI_VERB("no pending event found\n");
goto exit_bw_process;
goto exit_bw_scale_process;
}
/* if rp points to base, we need to wrap it around */
@ -1467,6 +1450,13 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
dev_rp = ev_ring->base + ev_ring->len;
dev_rp--;
/* fast forward to currently processed element and recycle er */
ev_ring->rp = dev_rp;
ev_ring->wp = dev_rp - 1;
if (ev_ring->wp < ev_ring->base)
ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size;
mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring);
MHI_ASSERT(MHI_TRE_GET_EV_TYPE(dev_rp) != MHI_PKT_TYPE_BW_REQ_EVENT,
"!BW SCALE REQ event");
@ -1479,19 +1469,22 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
link_info.target_link_speed,
link_info.target_link_width);
/* fast forward to currently processed element and recycle er */
ev_ring->rp = dev_rp;
ev_ring->wp = dev_rp - 1;
if (ev_ring->wp < ev_ring->base)
ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size;
mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring);
read_lock_bh(&mhi_cntrl->pm_lock);
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
mhi_ring_er_db(mhi_event);
read_unlock_bh(&mhi_cntrl->pm_lock);
spin_unlock_bh(&mhi_event->lock);
atomic_inc(&mhi_cntrl->pending_pkts);
ret = mhi_device_get_sync(mhi_cntrl->mhi_dev,
MHI_VOTE_DEVICE | MHI_VOTE_BUS);
if (ret) {
atomic_dec(&mhi_cntrl->pending_pkts);
goto exit_bw_scale_process;
}
mutex_lock(&mhi_cntrl->pm_mutex);
ret = mhi_cntrl->bw_scale(mhi_cntrl, &link_info);
if (!ret)
*cur_info = link_info;
@ -1501,17 +1494,17 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
read_lock_bh(&mhi_cntrl->pm_lock);
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bw_scale_db, 0,
MHI_BW_SCALE_RESULT(result,
link_info.sequence_num));
mhi_cntrl->wake_put(mhi_cntrl, false);
MHI_BW_SCALE_RESULT(result,
link_info.sequence_num));
read_unlock_bh(&mhi_cntrl->pm_lock);
exit_bw_process:
mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS);
atomic_dec(&mhi_cntrl->pending_pkts);
mutex_unlock(&mhi_cntrl->pm_mutex);
exit_no_lock:
MHI_VERB("exit er_index:%u\n", mhi_event->er_index);
exit_bw_scale_process:
MHI_VERB("exit er_index:%u ret:%d\n", mhi_event->er_index, ret);
return ret;
}