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

Commit 649971df authored by Bhaumik Bhatt's avatar Bhaumik Bhatt
Browse files

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: default avatarBhaumik Bhatt <bbhatt@codeaurora.org>
parent a6ae9f82
Loading
Loading
Loading
Loading
+25 −32
Original line number Diff line number Diff line
@@ -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;
@@ -1503,15 +1496,15 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *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);
	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;
}