@@ -37,6 +37,7 @@
[DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE",
[DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR",
[DEV_ST_TRANSITION_DISABLE] = "DISABLE",
+ [DEV_ST_TRANSITION_FATAL] = "FATAL SHUTDOWN",
};
const char * const mhi_state_str[MHI_STATE_MAX] = {
@@ -388,6 +388,7 @@ enum dev_st_transition {
DEV_ST_TRANSITION_MISSION_MODE,
DEV_ST_TRANSITION_SYS_ERR,
DEV_ST_TRANSITION_DISABLE,
+ DEV_ST_TRANSITION_FATAL,
DEV_ST_TRANSITION_MAX,
};
@@ -37,9 +37,10 @@
* M0 -> FW_DL_ERR
* M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
* L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
- * L2: SHUTDOWN_PROCESS -> DISABLE
+ * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT
+ * SHUTDOWN_PROCESS -> DISABLE
* L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
- * LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
+ * LD_ERR_FATAL_DETECT -> DISABLE
*/
static struct mhi_pm_transitions const dev_state_transitions[] = {
/* L0 States */
@@ -72,7 +73,7 @@
{
MHI_PM_M3,
MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT |
- MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT
+ MHI_PM_LD_ERR_FATAL_DETECT
},
{
MHI_PM_M3_EXIT,
@@ -103,7 +104,7 @@
/* L3 States */
{
MHI_PM_LD_ERR_FATAL_DETECT,
- MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS
+ MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_DISABLE
},
};
@@ -667,7 +668,11 @@ void mhi_pm_st_worker(struct work_struct *work)
break;
case DEV_ST_TRANSITION_DISABLE:
mhi_pm_disable_transition
- (mhi_cntrl, MHI_PM_SHUTDOWN_PROCESS);
+ (mhi_cntrl, MHI_PM_SHUTDOWN_PROCESS);
+ break;
+ case DEV_ST_TRANSITION_FATAL:
+ mhi_pm_disable_transition
+ (mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT);
break;
default:
break;
@@ -1040,6 +1045,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
{
enum mhi_pm_state cur_state;
+ enum dev_st_transition next_state = DEV_ST_TRANSITION_DISABLE;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
/* If it's not a graceful shutdown, force MHI to linkdown state */
@@ -1054,9 +1060,11 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
dev_dbg(dev, "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));
+ else
+ next_state = DEV_ST_TRANSITION_FATAL;
}
- mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
+ mhi_queue_state_transition(mhi_cntrl, next_state);
/* Wait for shutdown to complete */
flush_work(&mhi_cntrl->st_worker);
If MHI were to attempt a device shutdown following an assumption that the device is inaccessible, the host currently moves to a state where device register accesses are allowed when they should not be. This would end up allowing accesses to device register space when the link is inaccessible which can result in NOC errors to be observed on the host. Improve shutdown handling so as to prevent these outcomes and do not move the MHI PM state to a register accessible state after device is assumed to be inaccessible. Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org> --- drivers/bus/mhi/core/init.c | 1 + drivers/bus/mhi/core/internal.h | 1 + drivers/bus/mhi/core/pm.c | 20 ++++++++++++++------ 3 files changed, 16 insertions(+), 6 deletions(-)