From 487f688a87f2aee20928c1c1b3ffb01ca25746e9 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 12 Jan 2021 10:39:18 +0530 Subject: [PATCH] msm: mhi_dev: Avoid BME check while sending ready On some x86 based Root complex devices we observe that BME gets set during PBL initialization sequence and gets cleared if the BAR configuration is yet to be complete. So depending on the timing of AMSS boot duration, when we read the PCIE20_COMMAND_STATUS register bit(5) during BME IRQ, three scenarios can happen. 1. AMSS boots quicker: The BME bit is set, we set dev->enumerated flag and indicate EP_PCIE_LINK_ENABLED and initiate MHI which in turn continues to do MMIO initialization sequence. This sequence involves call to mhi_dev_sm_set_ready() and mhi_dev_sm_init() APIs which check for ep_pcie_get_linkstatus() API which might end up failing thus preventing MHI from moving to ready state. 2. The BME bit is already cleared and set again before the first BME IRQ. So there is no disruption in the code flow. 3. The BME bit is cleared and hence we do not set dev->enumerated. The normal code flow happens as part of 2nd BME IRQ. In (2) and (3) there are no issues, but in (1) during mhi_dev_resume_mmio_mhi_init() we call ep_pcie_register_event() which will overwrite the previous EP_PCIE_EVENT_LINKUP registration. So during the 2nd BME IRQ that gets fired, EP PCIE driver does not give a callback to MHI as EP_PCIE_EVENT_LINKUP is not registered by MHI anymore. In current implementation, APIs mhi_dev_sm_set_ready() or mhi_dev_sm_init() fail as BME is deasserted. This results in MHI host driver not getting ready state. mhi_dev_resume_mmio_mhi_init() is called only if BME is set, mhi_dev_sm_set_ready() and mhi_dev_sm_init() APIs are called as part of this. As these APIs are called only if BME is set, BME check inside these APIs is not really needed. To avoid the issue of not sending ready state, removing checks for BME in mhi_dev_sm_set_ready() and mhi_dev_sm_init() APIs, so that ready state is sent to host and M0 is received after this. Added a warning log before polling for M0 to know if BME is not set again by host. Change-Id: I211e9e20e05211d2a0c6f0972e1468a4d452ff5d Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/mhi_dev/mhi.c | 3 +++ drivers/platform/msm/mhi_dev/mhi_sm.c | 25 ++----------------------- drivers/platform/msm/mhi_dev/mhi_sm.h | 9 ++++++++- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 68e52b8191c9..d7d9ecad8d73 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -3936,6 +3936,9 @@ static void mhi_dev_enable(struct work_struct *work) "Cleared reset before waiting for M0\n"); } + if (ep_pcie_get_linkstatus(mhi->phandle) != EP_PCIE_LINK_ENABLED) + mhi_log(MHI_MSG_ERROR, "warning: PCIe BME unset error"); + while (state != MHI_DEV_M0_STATE && ((max_cnt < MHI_SUSPEND_TIMEOUT) || mhi->no_m0_timeout)) { /* Wait for Host to set the M0 state */ diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 5669fcfbd16a..89190bfeadfc 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -96,12 +96,6 @@ static inline const char *mhi_sm_mstate_str(enum mhi_dev_state state) return str; } -enum mhi_sm_ep_pcie_state { - MHI_SM_EP_PCIE_LINK_DISABLE, - MHI_SM_EP_PCIE_D0_STATE, - MHI_SM_EP_PCIE_D3_HOT_STATE, - MHI_SM_EP_PCIE_D3_COLD_STATE, -}; static inline const char *mhi_sm_dstate_str(enum mhi_sm_ep_pcie_state state) { @@ -1106,8 +1100,6 @@ unlock_and_exit: int mhi_dev_sm_init(struct mhi_dev *mhi_dev) { int res; - enum ep_pcie_link_status link_state; - MHI_SM_FUNC_ENTRY(); if (!mhi_dev) { @@ -1137,11 +1129,7 @@ int mhi_dev_sm_init(struct mhi_dev *mhi_dev) atomic_set(&mhi_sm_ctx->pending_device_events, 0); atomic_set(&mhi_sm_ctx->pending_pcie_events, 0); - link_state = ep_pcie_get_linkstatus(mhi_sm_ctx->mhi_dev->phandle); - if (link_state == EP_PCIE_LINK_ENABLED) - mhi_sm_ctx->d_state = MHI_SM_EP_PCIE_D0_STATE; - else - mhi_sm_ctx->d_state = MHI_SM_EP_PCIE_LINK_DISABLE; + mhi_sm_ctx->d_state = MHI_SM_EP_PCIE_D0_STATE; MHI_SM_FUNC_EXIT(); return 0; @@ -1238,16 +1226,7 @@ int mhi_dev_sm_set_ready(void) goto unlock_and_exit; } - if (mhi_sm_ctx->d_state != MHI_SM_EP_PCIE_D0_STATE) { - if (ep_pcie_get_linkstatus(mhi_sm_ctx->mhi_dev->phandle) == - EP_PCIE_LINK_ENABLED) { - mhi_sm_ctx->d_state = MHI_SM_EP_PCIE_D0_STATE; - } else { - MHI_SM_ERR("ERROR: ep-pcie link is not enabled\n"); - res = -EPERM; - goto unlock_and_exit; - } - } + mhi_sm_ctx->d_state = MHI_SM_EP_PCIE_D0_STATE; /* verify that MHISTATUS is configured to RESET*/ mhi_dev_mmio_masked_read(mhi_sm_ctx->mhi_dev, diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h index e061fed208ea..80ed0086472f 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.h +++ b/drivers/platform/msm/mhi_dev/mhi_sm.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015,2017-2018,2020 The Linux Foundation. All rights reserved.*/ +/* Copyright (c) 2015,2017-2018,2020-2021 The Linux Foundation. All rights reserved.*/ #ifndef MHI_SM_H #define MHI_SM_H @@ -31,6 +31,13 @@ enum mhi_dev_event { MHI_DEV_EVENT_MAX }; +enum mhi_sm_ep_pcie_state { + MHI_SM_EP_PCIE_LINK_DISABLE, + MHI_SM_EP_PCIE_D0_STATE, + MHI_SM_EP_PCIE_D3_HOT_STATE, + MHI_SM_EP_PCIE_D3_COLD_STATE, +}; + int mhi_dev_sm_init(struct mhi_dev *dev); int mhi_dev_sm_exit(struct mhi_dev *dev); int mhi_dev_sm_set_ready(void);