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 <bbhatt@codeaurora.org>
This commit is contained in:
Bhaumik Bhatt 2020-02-06 18:27:59 -08:00 • committed by Hemant Kumar
commit a71b413373
2 changed files with 49 additions and 35 deletions

View file

@ -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 */

View file

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