From a71b4133736d5458b8babeee1f19265ca579c4dc Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 6 Feb 2020 18:27:59 -0800 Subject: [PATCH] mhi: core: serialize execution environment and power off changes Execution environment and power off changes can be serialized to avoid changing these important controller variables from multiple places and serialize handling of all state transitions. Change-Id: I394e5ff4992d7c911e3889f96057d8467d79509c Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_main.c | 51 +++++++++++++++++++-------------- drivers/bus/mhi/core/mhi_pm.c | 33 ++++++++++++--------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 86b33832f611..a6fe4f261cb5 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1294,6 +1294,10 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, TO_MHI_EXEC_STR(event)); switch (event) { case MHI_EE_SBL: + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->ee = MHI_EE_SBL; + write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); st = MHI_ST_TRANSITION_SBL; break; case MHI_EE_WFW: @@ -1301,13 +1305,6 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, st = MHI_ST_TRANSITION_MISSION_MODE; break; case MHI_EE_RDDM: - mhi_cntrl->status_cb(mhi_cntrl, - mhi_cntrl->priv_data, - MHI_CB_EE_RDDM); - write_lock_irq(&mhi_cntrl->pm_lock); - mhi_cntrl->ee = event; - write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up_all(&mhi_cntrl->state_event); break; default: MHI_ERR("Unhandled EE event:%s\n", @@ -1674,13 +1671,17 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) } state = mhi_get_mhi_state(mhi_cntrl); - ee = mhi_cntrl->ee; - mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); - MHI_LOG("local ee: %s device ee:%s dev_state:%s\n", - TO_MHI_EXEC_STR(ee), + ee = mhi_get_exec_env(mhi_cntrl); + MHI_LOG("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)); + if (mhi_cntrl->power_down) { + write_unlock_irq(&mhi_cntrl->pm_lock); + goto exit_intvec; + } + if (state == MHI_STATE_SYS_ERR) { MHI_ERR("MHI system error detected\n"); pm_state = mhi_tryset_pm_state(mhi_cntrl, @@ -1688,20 +1689,28 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) } write_unlock_irq(&mhi_cntrl->pm_lock); - /* if device in rddm don't bother processing sys error */ - if (mhi_cntrl->ee == MHI_EE_RDDM && ee != MHI_EE_DISABLE_TRANSITION) { - if (mhi_cntrl->ee != ee) { - mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, - MHI_CB_EE_RDDM); - wake_up_all(&mhi_cntrl->state_event); - - /* notify critical clients with early notifications */ - mhi_control_error(mhi_cntrl); + if (ee == MHI_EE_RDDM) { + write_lock_irq(&mhi_cntrl->pm_lock); + if (mhi_cntrl->ee == MHI_EE_RDDM) { + write_unlock_irq(&mhi_cntrl->pm_lock); + goto exit_intvec; } + mhi_cntrl->ee = MHI_EE_RDDM; + write_unlock_irq(&mhi_cntrl->pm_lock); + + MHI_ERR("RDDM event occurred!\n"); + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, + MHI_CB_EE_RDDM); + wake_up_all(&mhi_cntrl->state_event); + + /* notify critical clients with early notifications */ + mhi_control_error(mhi_cntrl); + goto exit_intvec; } - if (pm_state == MHI_PM_SYS_ERR_DETECT) { + /* if device is in RDDM, don't bother processing SYS_ERR */ + if (ee != MHI_EE_RDDM && pm_state == MHI_PM_SYS_ERR_DETECT) { wake_up_all(&mhi_cntrl->state_event); /* for fatal errors, we let controller decide next step */ diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 34a8fea6df03..71c07fb84811 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -474,12 +474,16 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); - if (!MHI_IN_MISSION_MODE(ee)) + if (!MHI_IN_MISSION_MODE(ee)) { + MHI_ERR("Invalid EE:%s\n", TO_MHI_EXEC_STR(ee)); return -EIO; + } mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_EE_MISSION_MODE); + write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = ee; + write_unlock_irq(&mhi_cntrl->pm_lock); wake_up_all(&mhi_cntrl->state_event); @@ -585,8 +589,6 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, mhi_cntrl->ee = MHI_EE_DISABLE_TRANSITION; mhi_cntrl->dev_state = MHI_STATE_RESET; } - /* notify controller of power down regardless of state transitions */ - mhi_cntrl->power_down = true; write_unlock_irq(&mhi_cntrl->pm_lock); /* wake up any threads waiting for state transitions */ @@ -830,6 +832,10 @@ void mhi_process_sys_err(struct mhi_controller *mhi_cntrl) return; } + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->power_down = true; + write_unlock_irq(&mhi_cntrl->pm_lock); + mhi_queue_disable_transition(mhi_cntrl, MHI_PM_SYS_ERR_PROCESS); } @@ -855,14 +861,9 @@ void mhi_pm_st_worker(struct work_struct *work) if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); - if (MHI_IN_PBL(mhi_cntrl->ee)) - mhi_fw_load_handler(mhi_cntrl); + mhi_fw_load_handler(mhi_cntrl); break; case MHI_ST_TRANSITION_SBL: - write_lock_irq(&mhi_cntrl->pm_lock); - mhi_cntrl->ee = MHI_EE_SBL; - write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up_all(&mhi_cntrl->state_event); mhi_create_devices(mhi_cntrl); break; case MHI_ST_TRANSITION_MISSION_MODE: @@ -949,6 +950,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) } mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0); + mhi_cntrl->power_down = false; mhi_cntrl->pm_state = MHI_PM_POR; mhi_cntrl->ee = MHI_EE_MAX; current_ee = mhi_get_exec_env(mhi_cntrl); @@ -976,6 +978,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) return 0; error_bhi_offset: + mhi_cntrl->power_down = true; mhi_deinit_free_irq(mhi_cntrl); error_setup_irq: @@ -1034,21 +1037,23 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) enum MHI_PM_STATE cur_state; enum MHI_PM_STATE transition_state = MHI_PM_SHUTDOWN_PROCESS; + mutex_lock(&mhi_cntrl->pm_mutex); + + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->power_down = true; /* if it's not graceful shutdown, force MHI to a linkdown state */ if (!graceful) { - mutex_lock(&mhi_cntrl->pm_mutex); - write_lock_irq(&mhi_cntrl->pm_lock); cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT); - write_unlock_irq(&mhi_cntrl->pm_lock); - mutex_unlock(&mhi_cntrl->pm_mutex); if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) MHI_ERR("Failed to move to state:%s from:%s\n", to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT), to_mhi_pm_state_str(mhi_cntrl->pm_state)); - transition_state = MHI_PM_SHUTDOWN_NO_ACCESS; } + write_unlock_irq(&mhi_cntrl->pm_lock); + + mutex_unlock(&mhi_cntrl->pm_mutex); mhi_queue_disable_transition(mhi_cntrl, transition_state);