Loading drivers/bus/mhi/core/mhi_init.c +78 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/list.h> #include <linux/of.h> #include <linux/module.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/wait.h> #include <linux/mhi.h> Loading Loading @@ -73,6 +74,7 @@ static const char * const mhi_pm_state_str[] = { [MHI_PM_BIT_M3] = "M3", [MHI_PM_BIT_M3_EXIT] = "M3->M0", [MHI_PM_BIT_FW_DL_ERR] = "FW DL Error", [MHI_PM_BIT_DEVICE_ERR_DETECT] = "Device Error Detect", [MHI_PM_BIT_SYS_ERR_DETECT] = "SYS_ERR Detect", [MHI_PM_BIT_SYS_ERR_PROCESS] = "SYS_ERR Process", [MHI_PM_BIT_SHUTDOWN_PROCESS] = "SHUTDOWN Process", Loading Loading @@ -105,6 +107,25 @@ const char *to_mhi_pm_state_str(enum MHI_PM_STATE state) return mhi_pm_state_str[index]; } static void mhi_time_async_cb(struct mhi_device *mhi_dev, u32 sequence, u64 local_time, u64 remote_time) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; MHI_LOG("Time response: seq:%llx local: %llu remote: %llu (ticks)\n", sequence, local_time, remote_time); } static void mhi_time_us_async_cb(struct mhi_device *mhi_dev, u32 sequence, u64 local_time, u64 remote_time) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; MHI_LOG("Time response: seq:%llx local: %llu remote: %llu (us)\n", sequence, LOCAL_TICKS_TO_US(local_time), REMOTE_TICKS_TO_US(remote_time)); } static ssize_t time_show(struct device *dev, struct device_attribute *attr, char *buf) Loading @@ -117,7 +138,8 @@ static ssize_t time_show(struct device *dev, ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n", Loading @@ -137,7 +159,8 @@ static ssize_t time_us_show(struct device *dev, ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n", Loading @@ -146,9 +169,59 @@ static ssize_t time_us_show(struct device *dev, } static DEVICE_ATTR_RO(time_us); static ssize_t time_async_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u32 seq = prandom_u32(); int ret; if (!seq) seq = 1; ret = mhi_get_remote_time(mhi_dev, seq, &mhi_time_async_cb); if (ret) { MHI_ERR("Failed to request time, seq:%llx, ret:%d\n", seq, ret); return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "Requested time asynchronously with seq:%llx\n", seq); } static DEVICE_ATTR_RO(time_async); static ssize_t time_us_async_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u32 seq = prandom_u32(); int ret; if (!seq) seq = 1; ret = mhi_get_remote_time(mhi_dev, seq, &mhi_time_us_async_cb); if (ret) { MHI_ERR("Failed to request time, seq:%llx, ret:%d\n", seq, ret); return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "Requested time asynchronously with seq:%llx\n", seq); } static DEVICE_ATTR_RO(time_us_async); static struct attribute *mhi_tsync_attrs[] = { &dev_attr_time.attr, &dev_attr_time_us.attr, &dev_attr_time_async.attr, &dev_attr_time_us_async.attr, NULL, }; Loading Loading @@ -701,6 +774,8 @@ static int mhi_init_timesync(struct mhi_controller *mhi_cntrl) return er_index; } mhi_tsync->db_support = true; time_cfg_offset = time_offset + TIMESYNC_CFG_OFFSET; /* advertise host support */ Loading Loading @@ -762,7 +837,7 @@ static int mhi_init_bw_scale(struct mhi_controller *mhi_cntrl) /* No ER configured to support BW scale */ er_index = mhi_get_er_index(mhi_cntrl, MHI_ER_BW_SCALE_ELEMENT_TYPE); if (ret < 0) if (er_index < 0) return er_index; bw_cfg_offset += BW_SCALE_CFG_OFFSET; Loading drivers/bus/mhi/core/mhi_internal.h +7 −2 Original line number Diff line number Diff line Loading @@ -469,6 +469,7 @@ enum { MHI_PM_BIT_M3, MHI_PM_BIT_M3_EXIT, MHI_PM_BIT_FW_DL_ERR, MHI_PM_BIT_DEVICE_ERR_DETECT, MHI_PM_BIT_SYS_ERR_DETECT, MHI_PM_BIT_SYS_ERR_PROCESS, MHI_PM_BIT_SHUTDOWN_PROCESS, Loading @@ -488,6 +489,8 @@ enum MHI_PM_STATE { MHI_PM_M3_EXIT = BIT(MHI_PM_BIT_M3_EXIT), /* firmware download failure state */ MHI_PM_FW_DL_ERR = BIT(MHI_PM_BIT_FW_DL_ERR), /* error or shutdown detected or processing state */ MHI_PM_DEVICE_ERR_DETECT = BIT(MHI_PM_BIT_DEVICE_ERR_DETECT), MHI_PM_SYS_ERR_DETECT = BIT(MHI_PM_BIT_SYS_ERR_DETECT), MHI_PM_SYS_ERR_PROCESS = BIT(MHI_PM_BIT_SYS_ERR_PROCESS), MHI_PM_SHUTDOWN_PROCESS = BIT(MHI_PM_BIT_SHUTDOWN_PROCESS), Loading @@ -498,8 +501,9 @@ enum MHI_PM_STATE { #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | \ MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS | \ MHI_PM_FW_DL_ERR))) #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state >= MHI_PM_LD_ERR_FATAL_DETECT) #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & \ Loading Loading @@ -725,6 +729,7 @@ struct tsync_node { struct mhi_timesync { void __iomem *time_reg; u32 int_sequence; bool db_support; spinlock_t lock; /* list protection */ struct list_head head; }; Loading drivers/bus/mhi/core/mhi_main.c +33 −21 Original line number Diff line number Diff line Loading @@ -1228,6 +1228,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: Loading @@ -1235,13 +1239,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", Loading Loading @@ -1606,13 +1603,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); ee = mhi_get_exec_env(mhi_cntrl); MHI_LOG("local ee:%s device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(ee), 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, Loading @@ -1620,17 +1621,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 (ee == MHI_EE_RDDM) { write_lock_irq(&mhi_cntrl->pm_lock); if (mhi_cntrl->ee == MHI_EE_RDDM) { if (mhi_cntrl->ee != ee) { 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 */ Loading Loading @@ -2466,7 +2478,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, int ret; mutex_lock(&mhi_cntrl->tsync_mutex); /* not all devices support time feature */ /* not all devices support time features */ if (!mhi_tsync) { ret = -EIO; goto err_unlock; Loading Loading @@ -2537,9 +2549,9 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, struct tsync_node *tsync_node; int ret; /* not all devices support time feature */ /* not all devices support all time features */ mutex_lock(&mhi_cntrl->tsync_mutex); if (!mhi_tsync) { if (!mhi_tsync || !mhi_tsync->db_support) { ret = -EIO; goto error_unlock; } Loading drivers/bus/mhi/core/mhi_pm.c +64 −46 Original line number Diff line number Diff line Loading @@ -44,7 +44,8 @@ static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl); * M0 <--> M0 * M0 -> FW_DL_ERR * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR * L1: DEVICE_ERR_DETECT -> SYS_ERR_DETECT * SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT * SHUTDOWN_PROCESS -> DISABLE * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT Loading @@ -60,44 +61,53 @@ static struct mhi_pm_transitions const mhi_state_transitions[] = { { MHI_PM_POR, MHI_PM_POR | MHI_PM_DISABLE | MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M0, MHI_PM_M0 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M2, MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M0 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3_ENTER, MHI_PM_M3 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M3 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3, MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M3_EXIT | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3_EXIT, MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M0 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_FW_DL_ERR, MHI_PM_FW_DL_ERR | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_FW_DL_ERR | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, /* L1 States */ { MHI_PM_DEVICE_ERR_DETECT, MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_SYS_ERR_DETECT, MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS | Loading Loading @@ -461,12 +471,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); Loading Loading @@ -573,8 +587,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 */ Loading Loading @@ -823,6 +835,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); } Loading @@ -848,14 +864,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); 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: Loading Loading @@ -942,6 +953,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); Loading Loading @@ -969,6 +981,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: Loading @@ -985,7 +998,7 @@ EXPORT_SYMBOL(mhi_async_power_up); /* Transition MHI into error state and notify critical clients */ void mhi_control_error(struct mhi_controller *mhi_cntrl) { enum MHI_PM_STATE cur_state; enum MHI_PM_STATE cur_state, transition_state; struct mhi_sfr_info *sfr_info = mhi_cntrl->mhi_sfr; MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", Loading @@ -999,13 +1012,18 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl) sfr_info->buf_addr); } /* link is not down if device is in RDDM */ transition_state = (mhi_cntrl->ee == MHI_EE_RDDM) ? MHI_PM_DEVICE_ERR_DETECT : MHI_PM_LD_ERR_FATAL_DETECT; write_lock_irq(&mhi_cntrl->pm_lock); cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT); cur_state = mhi_tryset_pm_state(mhi_cntrl, transition_state); write_unlock_irq(&mhi_cntrl->pm_lock); if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) { /* proceed if we move to device error or are already in error state */ if (!MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { MHI_ERR("Failed to transition to state:%s from:%s\n", to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT), to_mhi_pm_state_str(transition_state), to_mhi_pm_state_str(cur_state)); goto exit_control_error; } Loading @@ -1030,21 +1048,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; /* 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); mhi_cntrl->power_down = true; /* if it's not graceful shutdown, force MHI to a linkdown state */ if (!graceful) { 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); Loading Loading @@ -1402,6 +1422,9 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client) } } /* do not process control events */ tasklet_disable(&mhi_cntrl->mhi_event->task); write_lock_irq(&mhi_cntrl->pm_lock); /* restore the states */ mhi_cntrl->pm_state = mhi_cntrl->saved_pm_state; Loading @@ -1414,19 +1437,14 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client) break; case MHI_PM_M2: read_lock_bh(&mhi_cntrl->pm_lock); /* * we're doing a double check of pm_state because by the time we * grab the pm_lock, device may have already initiate a M0 on * its own. If that's the case we should not be toggling device * wake. */ if (mhi_cntrl->pm_state == MHI_PM_M2) { mhi_cntrl->wake_get(mhi_cntrl, true); mhi_cntrl->wake_put(mhi_cntrl, true); } read_unlock_bh(&mhi_cntrl->pm_lock); } /* now it's safe to process ctrl events */ tasklet_enable(&mhi_cntrl->mhi_event->task); /* * In fast suspend/resume case device is not aware host transition * to suspend state. So, device could be triggering a interrupt while Loading Loading
drivers/bus/mhi/core/mhi_init.c +78 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/list.h> #include <linux/of.h> #include <linux/module.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/wait.h> #include <linux/mhi.h> Loading Loading @@ -73,6 +74,7 @@ static const char * const mhi_pm_state_str[] = { [MHI_PM_BIT_M3] = "M3", [MHI_PM_BIT_M3_EXIT] = "M3->M0", [MHI_PM_BIT_FW_DL_ERR] = "FW DL Error", [MHI_PM_BIT_DEVICE_ERR_DETECT] = "Device Error Detect", [MHI_PM_BIT_SYS_ERR_DETECT] = "SYS_ERR Detect", [MHI_PM_BIT_SYS_ERR_PROCESS] = "SYS_ERR Process", [MHI_PM_BIT_SHUTDOWN_PROCESS] = "SHUTDOWN Process", Loading Loading @@ -105,6 +107,25 @@ const char *to_mhi_pm_state_str(enum MHI_PM_STATE state) return mhi_pm_state_str[index]; } static void mhi_time_async_cb(struct mhi_device *mhi_dev, u32 sequence, u64 local_time, u64 remote_time) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; MHI_LOG("Time response: seq:%llx local: %llu remote: %llu (ticks)\n", sequence, local_time, remote_time); } static void mhi_time_us_async_cb(struct mhi_device *mhi_dev, u32 sequence, u64 local_time, u64 remote_time) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; MHI_LOG("Time response: seq:%llx local: %llu remote: %llu (us)\n", sequence, LOCAL_TICKS_TO_US(local_time), REMOTE_TICKS_TO_US(remote_time)); } static ssize_t time_show(struct device *dev, struct device_attribute *attr, char *buf) Loading @@ -117,7 +138,8 @@ static ssize_t time_show(struct device *dev, ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n", Loading @@ -137,7 +159,8 @@ static ssize_t time_us_show(struct device *dev, ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n", Loading @@ -146,9 +169,59 @@ static ssize_t time_us_show(struct device *dev, } static DEVICE_ATTR_RO(time_us); static ssize_t time_async_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u32 seq = prandom_u32(); int ret; if (!seq) seq = 1; ret = mhi_get_remote_time(mhi_dev, seq, &mhi_time_async_cb); if (ret) { MHI_ERR("Failed to request time, seq:%llx, ret:%d\n", seq, ret); return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "Requested time asynchronously with seq:%llx\n", seq); } static DEVICE_ATTR_RO(time_async); static ssize_t time_us_async_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u32 seq = prandom_u32(); int ret; if (!seq) seq = 1; ret = mhi_get_remote_time(mhi_dev, seq, &mhi_time_us_async_cb); if (ret) { MHI_ERR("Failed to request time, seq:%llx, ret:%d\n", seq, ret); return scnprintf(buf, PAGE_SIZE, "Request failed or feature unsupported\n"); } return scnprintf(buf, PAGE_SIZE, "Requested time asynchronously with seq:%llx\n", seq); } static DEVICE_ATTR_RO(time_us_async); static struct attribute *mhi_tsync_attrs[] = { &dev_attr_time.attr, &dev_attr_time_us.attr, &dev_attr_time_async.attr, &dev_attr_time_us_async.attr, NULL, }; Loading Loading @@ -701,6 +774,8 @@ static int mhi_init_timesync(struct mhi_controller *mhi_cntrl) return er_index; } mhi_tsync->db_support = true; time_cfg_offset = time_offset + TIMESYNC_CFG_OFFSET; /* advertise host support */ Loading Loading @@ -762,7 +837,7 @@ static int mhi_init_bw_scale(struct mhi_controller *mhi_cntrl) /* No ER configured to support BW scale */ er_index = mhi_get_er_index(mhi_cntrl, MHI_ER_BW_SCALE_ELEMENT_TYPE); if (ret < 0) if (er_index < 0) return er_index; bw_cfg_offset += BW_SCALE_CFG_OFFSET; Loading
drivers/bus/mhi/core/mhi_internal.h +7 −2 Original line number Diff line number Diff line Loading @@ -469,6 +469,7 @@ enum { MHI_PM_BIT_M3, MHI_PM_BIT_M3_EXIT, MHI_PM_BIT_FW_DL_ERR, MHI_PM_BIT_DEVICE_ERR_DETECT, MHI_PM_BIT_SYS_ERR_DETECT, MHI_PM_BIT_SYS_ERR_PROCESS, MHI_PM_BIT_SHUTDOWN_PROCESS, Loading @@ -488,6 +489,8 @@ enum MHI_PM_STATE { MHI_PM_M3_EXIT = BIT(MHI_PM_BIT_M3_EXIT), /* firmware download failure state */ MHI_PM_FW_DL_ERR = BIT(MHI_PM_BIT_FW_DL_ERR), /* error or shutdown detected or processing state */ MHI_PM_DEVICE_ERR_DETECT = BIT(MHI_PM_BIT_DEVICE_ERR_DETECT), MHI_PM_SYS_ERR_DETECT = BIT(MHI_PM_BIT_SYS_ERR_DETECT), MHI_PM_SYS_ERR_PROCESS = BIT(MHI_PM_BIT_SYS_ERR_PROCESS), MHI_PM_SHUTDOWN_PROCESS = BIT(MHI_PM_BIT_SHUTDOWN_PROCESS), Loading @@ -498,8 +501,9 @@ enum MHI_PM_STATE { #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | \ MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS | \ MHI_PM_FW_DL_ERR))) #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state >= MHI_PM_LD_ERR_FATAL_DETECT) #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & \ Loading Loading @@ -725,6 +729,7 @@ struct tsync_node { struct mhi_timesync { void __iomem *time_reg; u32 int_sequence; bool db_support; spinlock_t lock; /* list protection */ struct list_head head; }; Loading
drivers/bus/mhi/core/mhi_main.c +33 −21 Original line number Diff line number Diff line Loading @@ -1228,6 +1228,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: Loading @@ -1235,13 +1239,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", Loading Loading @@ -1606,13 +1603,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); ee = mhi_get_exec_env(mhi_cntrl); MHI_LOG("local ee:%s device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(ee), 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, Loading @@ -1620,17 +1621,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 (ee == MHI_EE_RDDM) { write_lock_irq(&mhi_cntrl->pm_lock); if (mhi_cntrl->ee == MHI_EE_RDDM) { if (mhi_cntrl->ee != ee) { 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 */ Loading Loading @@ -2466,7 +2478,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, int ret; mutex_lock(&mhi_cntrl->tsync_mutex); /* not all devices support time feature */ /* not all devices support time features */ if (!mhi_tsync) { ret = -EIO; goto err_unlock; Loading Loading @@ -2537,9 +2549,9 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, struct tsync_node *tsync_node; int ret; /* not all devices support time feature */ /* not all devices support all time features */ mutex_lock(&mhi_cntrl->tsync_mutex); if (!mhi_tsync) { if (!mhi_tsync || !mhi_tsync->db_support) { ret = -EIO; goto error_unlock; } Loading
drivers/bus/mhi/core/mhi_pm.c +64 −46 Original line number Diff line number Diff line Loading @@ -44,7 +44,8 @@ static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl); * M0 <--> M0 * M0 -> FW_DL_ERR * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR * L1: DEVICE_ERR_DETECT -> SYS_ERR_DETECT * SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT * SHUTDOWN_PROCESS -> DISABLE * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT Loading @@ -60,44 +61,53 @@ static struct mhi_pm_transitions const mhi_state_transitions[] = { { MHI_PM_POR, MHI_PM_POR | MHI_PM_DISABLE | MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M0, MHI_PM_M0 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_FW_DL_ERR | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M2, MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M0 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3_ENTER, MHI_PM_M3 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M3 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3, MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M3_EXIT | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_M3_EXIT, MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_M0 | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_FW_DL_ERR, MHI_PM_FW_DL_ERR | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS MHI_PM_FW_DL_ERR | MHI_PM_DEVICE_ERR_DETECT | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, /* L1 States */ { MHI_PM_DEVICE_ERR_DETECT, MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_NO_ACCESS }, { MHI_PM_SYS_ERR_DETECT, MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS | Loading Loading @@ -461,12 +471,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); Loading Loading @@ -573,8 +587,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 */ Loading Loading @@ -823,6 +835,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); } Loading @@ -848,14 +864,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); 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: Loading Loading @@ -942,6 +953,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); Loading Loading @@ -969,6 +981,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: Loading @@ -985,7 +998,7 @@ EXPORT_SYMBOL(mhi_async_power_up); /* Transition MHI into error state and notify critical clients */ void mhi_control_error(struct mhi_controller *mhi_cntrl) { enum MHI_PM_STATE cur_state; enum MHI_PM_STATE cur_state, transition_state; struct mhi_sfr_info *sfr_info = mhi_cntrl->mhi_sfr; MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", Loading @@ -999,13 +1012,18 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl) sfr_info->buf_addr); } /* link is not down if device is in RDDM */ transition_state = (mhi_cntrl->ee == MHI_EE_RDDM) ? MHI_PM_DEVICE_ERR_DETECT : MHI_PM_LD_ERR_FATAL_DETECT; write_lock_irq(&mhi_cntrl->pm_lock); cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT); cur_state = mhi_tryset_pm_state(mhi_cntrl, transition_state); write_unlock_irq(&mhi_cntrl->pm_lock); if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) { /* proceed if we move to device error or are already in error state */ if (!MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { MHI_ERR("Failed to transition to state:%s from:%s\n", to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT), to_mhi_pm_state_str(transition_state), to_mhi_pm_state_str(cur_state)); goto exit_control_error; } Loading @@ -1030,21 +1048,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; /* 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); mhi_cntrl->power_down = true; /* if it's not graceful shutdown, force MHI to a linkdown state */ if (!graceful) { 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); Loading Loading @@ -1402,6 +1422,9 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client) } } /* do not process control events */ tasklet_disable(&mhi_cntrl->mhi_event->task); write_lock_irq(&mhi_cntrl->pm_lock); /* restore the states */ mhi_cntrl->pm_state = mhi_cntrl->saved_pm_state; Loading @@ -1414,19 +1437,14 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client) break; case MHI_PM_M2: read_lock_bh(&mhi_cntrl->pm_lock); /* * we're doing a double check of pm_state because by the time we * grab the pm_lock, device may have already initiate a M0 on * its own. If that's the case we should not be toggling device * wake. */ if (mhi_cntrl->pm_state == MHI_PM_M2) { mhi_cntrl->wake_get(mhi_cntrl, true); mhi_cntrl->wake_put(mhi_cntrl, true); } read_unlock_bh(&mhi_cntrl->pm_lock); } /* now it's safe to process ctrl events */ tasklet_enable(&mhi_cntrl->mhi_event->task); /* * In fast suspend/resume case device is not aware host transition * to suspend state. So, device could be triggering a interrupt while Loading