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);