Skip to content

Commit a2ce11b

Browse files
quic-jhugogregkh
authored andcommitted
bus: mhi: host: Add MHI_PM_SYS_ERR_FAIL state
[ Upstream commit bce3f77 ] When processing a SYSERR, if the device does not respond to the MHI_RESET from the host, the host will be stuck in a difficult to recover state. The host will remain in MHI_PM_SYS_ERR_PROCESS and not clean up the host channels. Clients will not be notified of the SYSERR via the destruction of their channel devices, which means clients may think that the device is still up. Subsequent SYSERR events such as a device fatal error will not be processed as the state machine cannot transition from PROCESS back to DETECT. The only way to recover from this is to unload the mhi module (wipe the state machine state) or for the mhi controller to initiate SHUTDOWN. This issue was discovered by stress testing soc_reset events on AIC100 via the sysfs node. soc_reset is processed entirely in hardware. When the register write hits the endpoint hardware, it causes the soc to reset without firmware involvement. In stress testing, there is a rare race where soc_reset N will cause the soc to reset and PBL to signal SYSERR (fatal error). If soc_reset N+1 is triggered before PBL can process the MHI_RESET from the host, then the soc will reset again, and re-run PBL from the beginning. This will cause PBL to lose all state. PBL will be waiting for the host to respond to the new syserr, but host will be stuck expecting the previous MHI_RESET to be processed. Additionally, the AMSS EE firmware (QSM) was hacked to synthetically reproduce the issue by simulating a FW hang after the QSM issued a SYSERR. In this case, soc_reset would not recover the device. For this failure case, to recover the device, we need a state similar to PROCESS, but can transition to DETECT. There is not a viable existing state to use. POR has the needed transitions, but assumes the device is in a good state and could allow the host to attempt to use the device. Allowing PROCESS to transition to DETECT invites the possibility of parallel SYSERR processing which could get the host and device out of sync. Thus, invent a new state - MHI_PM_SYS_ERR_FAIL This essentially a holding state. It allows us to clean up the host elements that are based on the old state of the device (channels), but does not allow us to directly advance back to an operational state. It does allow the detection and processing of another SYSERR which may recover the device, or allows the controller to do a clean shutdown. Signed-off-by: Jeffrey Hugo <[email protected]> Reviewed-by: Carl Vanderlip <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 86a5318 commit a2ce11b

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

drivers/bus/mhi/host/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static const char * const mhi_pm_state_str[] = {
6262
[MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error",
6363
[MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect",
6464
[MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process",
65+
[MHI_PM_STATE_SYS_ERR_FAIL] = "SYS ERROR Failure",
6566
[MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process",
6667
[MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
6768
};

drivers/bus/mhi/host/internal.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ enum mhi_pm_state {
8888
MHI_PM_STATE_FW_DL_ERR,
8989
MHI_PM_STATE_SYS_ERR_DETECT,
9090
MHI_PM_STATE_SYS_ERR_PROCESS,
91+
MHI_PM_STATE_SYS_ERR_FAIL,
9192
MHI_PM_STATE_SHUTDOWN_PROCESS,
9293
MHI_PM_STATE_LD_ERR_FATAL_DETECT,
9394
MHI_PM_STATE_MAX
@@ -104,14 +105,16 @@ enum mhi_pm_state {
104105
#define MHI_PM_FW_DL_ERR BIT(7)
105106
#define MHI_PM_SYS_ERR_DETECT BIT(8)
106107
#define MHI_PM_SYS_ERR_PROCESS BIT(9)
107-
#define MHI_PM_SHUTDOWN_PROCESS BIT(10)
108+
#define MHI_PM_SYS_ERR_FAIL BIT(10)
109+
#define MHI_PM_SHUTDOWN_PROCESS BIT(11)
108110
/* link not accessible */
109-
#define MHI_PM_LD_ERR_FATAL_DETECT BIT(11)
111+
#define MHI_PM_LD_ERR_FATAL_DETECT BIT(12)
110112

111113
#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
112114
MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
113115
MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
114-
MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR)))
116+
MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | \
117+
MHI_PM_FW_DL_ERR)))
115118
#define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR)
116119
#define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT)
117120
#define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access)

drivers/bus/mhi/host/pm.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
* M0 <--> M0
3737
* M0 -> FW_DL_ERR
3838
* M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
39-
* L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
39+
* L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS
40+
* SYS_ERR_PROCESS -> SYS_ERR_FAIL
41+
* SYS_ERR_FAIL -> SYS_ERR_DETECT
42+
* SYS_ERR_PROCESS --> POR
4043
* L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT
4144
* SHUTDOWN_PROCESS -> DISABLE
4245
* L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
@@ -93,7 +96,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = {
9396
},
9497
{
9598
MHI_PM_SYS_ERR_PROCESS,
96-
MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS |
99+
MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS |
100+
MHI_PM_LD_ERR_FATAL_DETECT
101+
},
102+
{
103+
MHI_PM_SYS_ERR_FAIL,
104+
MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
97105
MHI_PM_LD_ERR_FATAL_DETECT
98106
},
99107
/* L2 States */
@@ -629,7 +637,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
629637
!in_reset, timeout);
630638
if (!ret || in_reset) {
631639
dev_err(dev, "Device failed to exit MHI Reset state\n");
632-
goto exit_sys_error_transition;
640+
write_lock_irq(&mhi_cntrl->pm_lock);
641+
cur_state = mhi_tryset_pm_state(mhi_cntrl,
642+
MHI_PM_SYS_ERR_FAIL);
643+
write_unlock_irq(&mhi_cntrl->pm_lock);
644+
/* Shutdown may have occurred, otherwise cleanup now */
645+
if (cur_state != MHI_PM_SYS_ERR_FAIL)
646+
goto exit_sys_error_transition;
633647
}
634648

635649
/*

0 commit comments

Comments
 (0)