diff mbox series

[v5,3/3] bus: mhi: core: Process execution environment changes serially

Message ID 1613776298-35560-4-git-send-email-bbhatt@codeaurora.org (mailing list archive)
State Superseded
Headers show
Series Serialize execution environment changes for MHI | expand

Commit Message

Bhaumik Bhatt Feb. 19, 2021, 11:11 p.m. UTC
In current design, whenever the BHI interrupt is fired, the
execution environment is updated. This can cause race conditions
and impede ongoing power up/down processing. For example, if a
power down is in progress, MHI host updates to a local "disabled"
execution environment. If a BHI interrupt fires later, that value
gets replaced with one from the BHI EE register. This impacts the
controller as it does not expect multiple RDDM execution
environment change status callbacks as an example. Another issue
would be that the device can enter mission mode and the execution
environment is updated, while device creation for SBL channels is
still going on due to slower PM state worker thread run, leading
to multiple attempts at opening the same channel.

We must handle and wait for SYS_ERROR in any case to facilitate
clean-up for the controller and handle RDDM. Ensure that EE
changes are handled only from appropriate places and occur one
after another and handle only PBL modes or RDDM EE changes as
critical events directly from the interrupt handler. This also
makes sure that we use the correct execution environment to notify
the controller driver when the device resets to one of the PBL
execution environments.

Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org>
---
 drivers/bus/mhi/core/main.c | 38 +++++++++++++++++++-------------------
 drivers/bus/mhi/core/pm.c   |  5 +++--
 2 files changed, 22 insertions(+), 21 deletions(-)

Comments

kernel test robot Feb. 20, 2021, 1:51 a.m. UTC | #1
Hi Bhaumik,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.11 next-20210219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Bhaumik-Bhatt/Serialize-execution-environment-changes-for-MHI/20210220-071426
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f40ddce88593482919761f74910f42f4b84c004b
config: mips-randconfig-r033-20210219 (attached as .config)
compiler: mipsel-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/e38872b38ede9c5c1706cd11bf5792f8dc436fcf
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Bhaumik-Bhatt/Serialize-execution-environment-changes-for-MHI/20210220-071426
        git checkout e38872b38ede9c5c1706cd11bf5792f8dc436fcf
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/bus/mhi/core/main.c: In function 'mhi_intvec_threaded_handler':
>> drivers/bus/mhi/core/main.c:436:17: warning: this statement may fall through [-Wimplicit-fallthrough=]
     436 |   mhi_cntrl->ee = ee;
         |   ~~~~~~~~~~~~~~^~~~
   drivers/bus/mhi/core/main.c:438:2: note: here
     438 |  default:
         |  ^~~~~~~


vim +436 drivers/bus/mhi/core/main.c

   392	
   393	irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
   394	{
   395		struct mhi_controller *mhi_cntrl = priv;
   396		struct device *dev = &mhi_cntrl->mhi_dev->dev;
   397		enum mhi_state state = MHI_STATE_MAX;
   398		enum mhi_pm_state pm_state = 0;
   399		enum mhi_ee_type ee = MHI_EE_MAX;
   400	
   401		write_lock_irq(&mhi_cntrl->pm_lock);
   402		if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
   403			write_unlock_irq(&mhi_cntrl->pm_lock);
   404			goto exit_intvec;
   405		}
   406	
   407		state = mhi_get_mhi_state(mhi_cntrl);
   408		ee = mhi_get_exec_env(mhi_cntrl);
   409		dev_dbg(dev, "local ee:%s device ee:%s dev_state:%s\n",
   410			TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_EXEC_STR(ee),
   411			TO_MHI_STATE_STR(state));
   412	
   413		if (state == MHI_STATE_SYS_ERR) {
   414			dev_dbg(dev, "System error detected\n");
   415			pm_state = mhi_tryset_pm_state(mhi_cntrl,
   416						       MHI_PM_SYS_ERR_DETECT);
   417		}
   418		write_unlock_irq(&mhi_cntrl->pm_lock);
   419	
   420		if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee)
   421			goto exit_intvec;
   422	
   423		switch (ee) {
   424		case MHI_EE_RDDM:
   425			/* proceed if power down is not already in progress */
   426			if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) {
   427				mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM);
   428				mhi_cntrl->ee = ee;
   429				wake_up_all(&mhi_cntrl->state_event);
   430			}
   431			break;
   432		case MHI_EE_PBL:
   433		case MHI_EE_EDL:
   434		case MHI_EE_PTHRU:
   435			mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR);
 > 436			mhi_cntrl->ee = ee;
   437		/* continue */
   438		default:
   439			mhi_pm_sys_err_handler(mhi_cntrl);
   440			wake_up_all(&mhi_cntrl->state_event);
   441			break;
   442		}
   443	
   444	exit_intvec:
   445	
   446		return IRQ_HANDLED;
   447	}
   448	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c
index 58f1425..c55d6ec 100644
--- a/drivers/bus/mhi/core/main.c
+++ b/drivers/bus/mhi/core/main.c
@@ -428,7 +428,7 @@  irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
 	struct device *dev = &mhi_cntrl->mhi_dev->dev;
 	enum mhi_state state = MHI_STATE_MAX;
 	enum mhi_pm_state pm_state = 0;
-	enum mhi_ee_type ee = 0;
+	enum mhi_ee_type ee = MHI_EE_MAX;
 
 	write_lock_irq(&mhi_cntrl->pm_lock);
 	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
@@ -437,8 +437,7 @@  irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
 	}
 
 	state = mhi_get_mhi_state(mhi_cntrl);
-	ee = mhi_cntrl->ee;
-	mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
+	ee = mhi_get_exec_env(mhi_cntrl);
 	dev_dbg(dev, "local ee:%s device ee:%s dev_state:%s\n",
 		TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_EXEC_STR(ee),
 		TO_MHI_STATE_STR(state));
@@ -450,27 +449,28 @@  irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
 	}
 	write_unlock_irq(&mhi_cntrl->pm_lock);
 
-	 /* If device supports RDDM don't bother processing SYS error */
-	if (mhi_cntrl->rddm_image) {
-		/* host may be performing a device power down already */
-		if (!mhi_is_active(mhi_cntrl))
-			goto exit_intvec;
+	if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee)
+		goto exit_intvec;
 
-		if (mhi_cntrl->ee == MHI_EE_RDDM && mhi_cntrl->ee != ee) {
+	switch (ee) {
+	case MHI_EE_RDDM:
+		/* proceed if power down is not already in progress */
+		if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) {
 			mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM);
+			mhi_cntrl->ee = ee;
 			wake_up_all(&mhi_cntrl->state_event);
 		}
-		goto exit_intvec;
-	}
-
-	if (pm_state == MHI_PM_SYS_ERR_DETECT) {
+		break;
+	case MHI_EE_PBL:
+	case MHI_EE_EDL:
+	case MHI_EE_PTHRU:
+		mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR);
+		mhi_cntrl->ee = ee;
+	/* continue */
+	default:
+		mhi_pm_sys_err_handler(mhi_cntrl);
 		wake_up_all(&mhi_cntrl->state_event);
-
-		/* For fatal errors, we let controller decide next step */
-		if (MHI_IN_PBL(ee))
-			mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR);
-		else
-			mhi_pm_sys_err_handler(mhi_cntrl);
+		break;
 	}
 
 exit_intvec:
diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
index 44aa7eb..c870fa8 100644
--- a/drivers/bus/mhi/core/pm.c
+++ b/drivers/bus/mhi/core/pm.c
@@ -384,14 +384,15 @@  static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
 
 	write_lock_irq(&mhi_cntrl->pm_lock);
 	if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
-		mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
+		ee = mhi_get_exec_env(mhi_cntrl);
 
-	if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) {
+	if (!MHI_IN_MISSION_MODE(ee)) {
 		mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
 		write_unlock_irq(&mhi_cntrl->pm_lock);
 		wake_up_all(&mhi_cntrl->state_event);
 		return -EIO;
 	}
+	mhi_cntrl->ee = ee;
 	write_unlock_irq(&mhi_cntrl->pm_lock);
 
 	wake_up_all(&mhi_cntrl->state_event);