diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index d7d9ecad8d73..141ce1157e9c 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -39,7 +39,7 @@ /* Wait time on the device for Host to set BHI_INTVEC */ #define MHI_BHI_INTVEC_MAX_CNT 200 #define MHI_BHI_INTVEC_WAIT_MS 50 -#define MHI_WAKEUP_TIMEOUT_CNT 20 +#define MHI_WAKEUP_TIMEOUT_CNT 25 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 #define MHI_RING_PRIMARY_EVT_ID 1 diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 89190bfeadfc..ba8c9a19136e 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -12,6 +12,7 @@ #include "mhi_hwio.h" #include "mhi_sm.h" #include +#include #define MHI_SM_DBG(fmt, args...) \ mhi_log(MHI_MSG_DBG, fmt, ##args) @@ -28,6 +29,8 @@ #define PCIE_EP_TIMER_US 500000000 #define MHI_IPA_DISABLE_DELAY_MS 10 #define MHI_IPA_DISABLE_COUNTER 20 +/* Maximum wait time for D state transitions to D3hot */ +#define M3_DO_WAKEUP_TIMEOUT_MS 2500 static inline const char *mhi_sm_dev_event_str(enum mhi_dev_event state) @@ -734,7 +737,7 @@ exit: * mhi_sm_wakeup_host() - wakeup MHI-host *@event: MHI state chenge event * - * Sends wekup event to MHI-host via EP-PCIe, in case MHI is in M3 state. + * Sends wakeup event to MHI-host via EP-PCIe, in case MHI is in M3 state. * * Return: 0:success * negative: failure @@ -742,6 +745,7 @@ exit: static int mhi_sm_wakeup_host(enum mhi_dev_event event) { int res = 0; + int timeout = 0; enum ep_pcie_event pcie_event; MHI_SM_FUNC_ENTRY(); @@ -753,9 +757,33 @@ static int mhi_sm_wakeup_host(enum mhi_dev_event event) MHI_SM_ERR("Failed switching to M0 state\n"); } else if (mhi_sm_ctx->mhi_state == MHI_DEV_M3_STATE) { /* - * Check and send D3_HOT to enable waking up the host - * using inband PME. + * Handle host wakeup in M3 + D0 states. + * + * When a MHI WAKE request is received while device is in D0, + * wait for D3 and wakeup the host using inband PME. + * If the MHI state changes to M0 while waiting for D3, + * exit, since both MHI and the device are in active state. */ + if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D0_STATE) { + timeout = ktime_add_ms(ktime_get(), M3_DO_WAKEUP_TIMEOUT_MS); + while (1) { + /* Received M0 */ + if (mhi_sm_ctx->mhi_state == MHI_DEV_M0_STATE) + goto exit; + /* Received D3 state */ + if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE || + mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_COLD_STATE) + goto wakeup_host; + if (ktime_after(ktime_get(), timeout)) { + MHI_SM_ERR(mhi->vf_id, + "M3, D0 wakeup host is not supported %d\n", res); + goto exit; + } + usleep_range(1000, 2000); + } + } +wakeup_host: + /* Received D3hot or D3cold, send the wakeup request */ if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE) pcie_event = EP_PCIE_EVENT_PM_D3_HOT; else