diff mbox series

[v6,5/5] bus: mhi: ep: wake up host if the MHI state is in M3

Message ID 20240710-wakeup_host-v6-5-ef00f31ea38d@quicinc.com (mailing list archive)
State New
Delegated to: Manivannan Sadhasivam
Headers show
Series PCI: EPC: Add support to wake up host from D3 states | expand

Commit Message

Krishna Chaitanya Chundru July 10, 2024, 11:16 a.m. UTC
If the MHI state is in M3 then most probably the host kept the
device in D3 hot or D3 cold, due to that endpoint transactions will not
reach the host, endpoint needs to wakes up the host to bring the host
to D0 which eventually bring back the MHI state to M0.

while queueing packets if the MHI state is in M3 wakeup host to bring
back link to M0.

Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 drivers/bus/mhi/ep/main.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

Comments

Bjorn Helgaas July 11, 2024, 4:47 p.m. UTC | #1
On Wed, Jul 10, 2024 at 04:46:12PM +0530, Krishna chaitanya chundru wrote:
> If the MHI state is in M3 then most probably the host kept the
> device in D3 hot or D3 cold, due to that endpoint transactions will not
> reach the host, endpoint needs to wakes up the host to bring the host
> to D0 which eventually bring back the MHI state to M0.

s/needs to wakes up/needs to wake up/

s/D3 hot/D3hot/
s/D3 cold/D3cold/
to match other uses and make grep more effective.

> while queueing packets if the MHI state is in M3 wakeup host to bring
> back link to M0.

s/while/While/
s/MHI state is in M3/MHI is in M3/ (twice)

> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
>  drivers/bus/mhi/ep/main.c | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
> 
> diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
> index b3eafcf2a2c5..b8713e5c1e1a 100644
> --- a/drivers/bus/mhi/ep/main.c
> +++ b/drivers/bus/mhi/ep/main.c
> @@ -25,6 +25,26 @@ static DEFINE_IDA(mhi_ep_cntrl_ida);
>  static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id);
>  static int mhi_ep_destroy_device(struct device *dev, void *data);
>  
> +static int mhi_ep_wake_host(struct mhi_ep_cntrl *mhi_cntrl)
> +{
> +	enum mhi_state state;
> +	bool mhi_reset;
> +	u32 count = 0;
> +
> +	mhi_cntrl->wakeup_host(mhi_cntrl);
> +
> +	/* Wait for Host to set the M0 state */
> +	while (count++ < M0_WAIT_COUNT) {
> +		msleep(M0_WAIT_DELAY_MS);

Tangent: the "M0_WAIT_DELAY_MS" name suggests that is the maximum
delay, but it seems the actual maximum delay is
M0_WAIT_DELAY_MS * M0_WAIT_COUNT.

Tangent 2: unless there's a reason to be different, it would be nice
to use the same loop structure as the similar delay in mhi_ep_enable().

> +		mhi_ep_mmio_get_mhi_state(mhi_cntrl, &state, &mhi_reset);
> +		if (state == MHI_STATE_M0)
> +			return 0;
> +	}
> +
> +	return -ENODEV;
> +}
diff mbox series

Patch

diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index b3eafcf2a2c5..b8713e5c1e1a 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -25,6 +25,26 @@  static DEFINE_IDA(mhi_ep_cntrl_ida);
 static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id);
 static int mhi_ep_destroy_device(struct device *dev, void *data);
 
+static int mhi_ep_wake_host(struct mhi_ep_cntrl *mhi_cntrl)
+{
+	enum mhi_state state;
+	bool mhi_reset;
+	u32 count = 0;
+
+	mhi_cntrl->wakeup_host(mhi_cntrl);
+
+	/* Wait for Host to set the M0 state */
+	while (count++ < M0_WAIT_COUNT) {
+		msleep(M0_WAIT_DELAY_MS);
+
+		mhi_ep_mmio_get_mhi_state(mhi_cntrl, &state, &mhi_reset);
+		if (state == MHI_STATE_M0)
+			return 0;
+	}
+
+	return -ENODEV;
+}
+
 static int mhi_ep_send_event(struct mhi_ep_cntrl *mhi_cntrl, u32 ring_idx,
 			     struct mhi_ring_element *el, bool bei)
 {
@@ -564,6 +584,14 @@  int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
 
 	mutex_lock(&mhi_chan->lock);
 
+	if (mhi_cntrl->mhi_state == MHI_STATE_M3) {
+		ret = mhi_ep_wake_host(mhi_cntrl);
+		if (ret) {
+			dev_err(dev, "Failed to wakeup host\n");
+			goto err_exit;
+		}
+	}
+
 	do {
 		/* Don't process the transfer ring if the channel is not in RUNNING state */
 		if (mhi_chan->state != MHI_CH_STATE_RUNNING) {