| From 02b49cd1174527e611768fc2ce0f75a74dfec7ae Mon Sep 17 00:00:00 2001 |
| From: Baochen Qiang <bqiang@codeaurora.org> |
| Date: Mon, 21 Jun 2021 21:46:11 +0530 |
| Subject: bus: mhi: Wait for M2 state during system resume |
| |
| From: Baochen Qiang <bqiang@codeaurora.org> |
| |
| commit 02b49cd1174527e611768fc2ce0f75a74dfec7ae upstream. |
| |
| During system resume, MHI host triggers M3->M0 transition and then waits |
| for target device to enter M0 state. Once done, the device queues a state |
| change event into ctrl event ring and notifies MHI host by raising an |
| interrupt, where a tasklet is scheduled to process this event. In most |
| cases, the tasklet is served timely and wait operation succeeds. |
| |
| However, there are cases where CPU is busy and cannot serve this tasklet |
| for some time. Once delay goes long enough, the device moves itself to M1 |
| state and also interrupts MHI host after inserting a new state change |
| event to ctrl ring. Later when CPU finally has time to process the ring, |
| there will be two events: |
| |
| 1. For M3->M0 event, which is the first event to be processed queued first. |
| The tasklet handler serves the event, updates device state to M0 and |
| wakes up the task. |
| |
| 2. For M0->M1 event, which is processed later, the tasklet handler |
| triggers M1->M2 transition and updates device state to M2 directly, |
| then wakes up the MHI host (if it is still sleeping on this wait queue). |
| |
| Note that although MHI host has been woken up while processing the first |
| event, it may still has no chance to run before the second event is |
| processed. In other words, MHI host has to keep waiting till timeout |
| causing the M0 state to be missed. |
| |
| kernel log here: |
| ... |
| Apr 15 01:45:14 test-NUC8i7HVK kernel: [ 4247.911251] mhi 0000:06:00.0: Entered with PM state: M3, MHI state: M3 |
| Apr 15 01:45:14 test-NUC8i7HVK kernel: [ 4247.917762] mhi 0000:06:00.0: State change event to state: M0 |
| Apr 15 01:45:14 test-NUC8i7HVK kernel: [ 4247.917767] mhi 0000:06:00.0: State change event to state: M1 |
| Apr 15 01:45:14 test-NUC8i7HVK kernel: [ 4338.788231] mhi 0000:06:00.0: Did not enter M0 state, MHI state: M2, PM state: M2 |
| ... |
| |
| Fix this issue by simply adding M2 as a valid state for resume. |
| |
| Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 0c6b20a1d720 ("bus: mhi: core: Add support for MHI suspend and resume") |
| Signed-off-by: Baochen Qiang <bqiang@codeaurora.org> |
| Reviewed-by: Hemant Kumar <hemantk@codeaurora.org> |
| Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
| Link: https://lore.kernel.org/r/20210524040312.14409-1-bqiang@codeaurora.org |
| [mani: slightly massaged the commit message] |
| Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
| Link: https://lore.kernel.org/r/20210621161616.77524-4-manivannan.sadhasivam@linaro.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/bus/mhi/core/pm.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| --- a/drivers/bus/mhi/core/pm.c |
| +++ b/drivers/bus/mhi/core/pm.c |
| @@ -809,6 +809,7 @@ int mhi_pm_resume(struct mhi_controller |
| |
| ret = wait_event_timeout(mhi_cntrl->state_event, |
| mhi_cntrl->dev_state == MHI_STATE_M0 || |
| + mhi_cntrl->dev_state == MHI_STATE_M2 || |
| MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), |
| msecs_to_jiffies(mhi_cntrl->timeout_ms)); |
| |