lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <a02c31409d696075b155ef2d6ee33009@codeaurora.org> Date: Fri, 30 Oct 2020 12:34:07 -0700 From: Bhaumik Bhatt <bbhatt@...eaurora.org> To: Manivannan Sadhasivam <manivannan.sadhasivam@...aro.org> Cc: linux-arm-msm@...r.kernel.org, hemantk@...eaurora.org, jhugo@...eaurora.org, linux-kernel@...r.kernel.org Subject: Re: [PATCH v3 10/12] bus: mhi: core: Separate system error and power down handling Hi Mani, On 2020-10-30 07:06, Manivannan Sadhasivam wrote: > On Thu, Oct 29, 2020 at 09:10:55PM -0700, Bhaumik Bhatt wrote: >> Currently, there exist a set of if...else statements in the >> mhi_pm_disable_transition() function which make handling system >> error and disable transitions differently complex. To make that >> cleaner and facilitate differences in behavior, separate these >> two transitions for MHI host. >> > > And this results in a lot of duplicated code :/ > > Thanks, > Mani > I knew this was coming. Mainly, we can avoid adding confusing if...else statements that plague the current mhi_pm_disable_transition() function and in return for some duplicate code, we can make handling separate use cases easier as they could pop-up anytime in the future. >> Signed-off-by: Bhaumik Bhatt <bbhatt@...eaurora.org> >> --- >> drivers/bus/mhi/core/pm.c | 159 >> +++++++++++++++++++++++++++++++++++++++------- >> 1 file changed, 137 insertions(+), 22 deletions(-) >> >> diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c >> index 1d04e401..347ae7d 100644 >> --- a/drivers/bus/mhi/core/pm.c >> +++ b/drivers/bus/mhi/core/pm.c >> @@ -444,7 +444,7 @@ static int mhi_pm_mission_mode_transition(struct >> mhi_controller *mhi_cntrl) >> return ret; >> } >> >> -/* Handle SYS_ERR and Shutdown transitions */ >> +/* Handle shutdown transitions */ >> static void mhi_pm_disable_transition(struct mhi_controller >> *mhi_cntrl, >> enum mhi_pm_state transition_state) >> { >> @@ -460,10 +460,6 @@ static void mhi_pm_disable_transition(struct >> mhi_controller *mhi_cntrl, >> to_mhi_pm_state_str(mhi_cntrl->pm_state), >> to_mhi_pm_state_str(transition_state)); >> >> - /* We must notify MHI control driver so it can clean up first */ >> - if (transition_state == MHI_PM_SYS_ERR_PROCESS) >> - mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_SYS_ERROR); >> - >> mutex_lock(&mhi_cntrl->pm_mutex); >> write_lock_irq(&mhi_cntrl->pm_lock); >> prev_state = mhi_cntrl->pm_state; >> @@ -502,11 +498,8 @@ static void mhi_pm_disable_transition(struct >> mhi_controller *mhi_cntrl, >> MHICTRL_RESET_SHIFT, >> &in_reset) || >> !in_reset, timeout); >> - if ((!ret || in_reset) && cur_state == MHI_PM_SYS_ERR_PROCESS) { >> + if (!ret || in_reset) >> dev_err(dev, "Device failed to exit MHI Reset state\n"); >> - mutex_unlock(&mhi_cntrl->pm_mutex); >> - return; >> - } >> >> /* >> * Device will clear BHI_INTVEC as a part of RESET processing, >> @@ -566,19 +559,142 @@ static void mhi_pm_disable_transition(struct >> mhi_controller *mhi_cntrl, >> er_ctxt->wp = er_ctxt->rbase; >> } >> >> - if (cur_state == MHI_PM_SYS_ERR_PROCESS) { >> - mhi_ready_state_transition(mhi_cntrl); >> - } else { >> - /* Move to disable state */ >> - write_lock_irq(&mhi_cntrl->pm_lock); >> - cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_DISABLE); >> - write_unlock_irq(&mhi_cntrl->pm_lock); >> - if (unlikely(cur_state != MHI_PM_DISABLE)) >> - dev_err(dev, "Error moving from PM state: %s to: %s\n", >> - to_mhi_pm_state_str(cur_state), >> - to_mhi_pm_state_str(MHI_PM_DISABLE)); >> + /* Move to disable state */ >> + write_lock_irq(&mhi_cntrl->pm_lock); >> + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_DISABLE); >> + write_unlock_irq(&mhi_cntrl->pm_lock); >> + if (unlikely(cur_state != MHI_PM_DISABLE)) >> + dev_err(dev, "Error moving from PM state: %s to: %s\n", >> + to_mhi_pm_state_str(cur_state), >> + to_mhi_pm_state_str(MHI_PM_DISABLE)); >> + >> + dev_dbg(dev, "Exiting with PM state: %s, MHI state: %s\n", >> + to_mhi_pm_state_str(mhi_cntrl->pm_state), >> + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); >> + >> + mutex_unlock(&mhi_cntrl->pm_mutex); >> +} >> + >> +/* Handle system error transitions */ >> +static void mhi_pm_sys_error_transition(struct mhi_controller >> *mhi_cntrl) >> +{ >> + enum mhi_pm_state cur_state, prev_state; >> + struct mhi_event *mhi_event; >> + struct mhi_cmd_ctxt *cmd_ctxt; >> + struct mhi_cmd *mhi_cmd; >> + struct mhi_event_ctxt *er_ctxt; >> + struct device *dev = &mhi_cntrl->mhi_dev->dev; >> + int ret, i; >> + >> + dev_dbg(dev, "Transitioning from PM state: %s to: %s\n", >> + to_mhi_pm_state_str(mhi_cntrl->pm_state), >> + to_mhi_pm_state_str(MHI_PM_SYS_ERR_PROCESS)); >> + >> + /* We must notify MHI control driver so it can clean up first */ >> + mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_SYS_ERROR); >> + >> + mutex_lock(&mhi_cntrl->pm_mutex); >> + write_lock_irq(&mhi_cntrl->pm_lock); >> + prev_state = mhi_cntrl->pm_state; >> + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_SYS_ERR_PROCESS); >> + write_unlock_irq(&mhi_cntrl->pm_lock); >> + >> + if (cur_state != MHI_PM_SYS_ERR_PROCESS) { >> + dev_err(dev, "Failed to transition from PM state: %s to: %s\n", >> + to_mhi_pm_state_str(cur_state), >> + to_mhi_pm_state_str(MHI_PM_SYS_ERR_PROCESS)); >> + goto exit_sys_error_transition; >> + } >> + >> + mhi_cntrl->ee = MHI_EE_DISABLE_TRANSITION; >> + mhi_cntrl->dev_state = MHI_STATE_RESET; >> + >> + /* Wake up threads waiting for state transition */ >> + wake_up_all(&mhi_cntrl->state_event); >> + >> + /* Trigger MHI RESET so that the device will not access host memory >> */ >> + if (MHI_REG_ACCESS_VALID(prev_state)) { >> + u32 in_reset = -1; >> + unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms); >> + >> + dev_dbg(dev, "Triggering MHI Reset in device\n"); >> + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); >> + >> + /* Wait for the reset bit to be cleared by the device */ >> + ret = wait_event_timeout(mhi_cntrl->state_event, >> + mhi_read_reg_field(mhi_cntrl, >> + mhi_cntrl->regs, >> + MHICTRL, >> + MHICTRL_RESET_MASK, >> + MHICTRL_RESET_SHIFT, >> + &in_reset) || >> + !in_reset, timeout); >> + if (!ret || in_reset) { >> + dev_err(dev, "Device failed to exit MHI Reset state\n"); >> + goto exit_sys_error_transition; >> + } >> + >> + /* >> + * Device will clear BHI_INTVEC as a part of RESET processing, >> + * hence re-program it >> + */ >> + mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0); >> + } >> + >> + dev_dbg(dev, >> + "Waiting for all pending event ring processing to complete\n"); >> + mhi_event = mhi_cntrl->mhi_event; >> + for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { >> + if (mhi_event->offload_ev) >> + continue; >> + tasklet_kill(&mhi_event->task); >> } >> >> + /* Release lock and wait for all pending threads to complete */ >> + mutex_unlock(&mhi_cntrl->pm_mutex); >> + dev_dbg(dev, "Waiting for all pending threads to complete\n"); >> + wake_up_all(&mhi_cntrl->state_event); >> + >> + dev_dbg(dev, "Reset all active channels and remove MHI devices\n"); >> + device_for_each_child(mhi_cntrl->cntrl_dev, NULL, >> mhi_destroy_device); >> + >> + mutex_lock(&mhi_cntrl->pm_mutex); >> + >> + WARN_ON(atomic_read(&mhi_cntrl->dev_wake)); >> + WARN_ON(atomic_read(&mhi_cntrl->pending_pkts)); >> + >> + /* Reset the ev rings and cmd rings */ >> + dev_dbg(dev, "Resetting EV CTXT and CMD CTXT\n"); >> + mhi_cmd = mhi_cntrl->mhi_cmd; >> + cmd_ctxt = mhi_cntrl->mhi_ctxt->cmd_ctxt; >> + for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++, cmd_ctxt++) { >> + struct mhi_ring *ring = &mhi_cmd->ring; >> + >> + ring->rp = ring->base; >> + ring->wp = ring->base; >> + cmd_ctxt->rp = cmd_ctxt->rbase; >> + cmd_ctxt->wp = cmd_ctxt->rbase; >> + } >> + >> + mhi_event = mhi_cntrl->mhi_event; >> + er_ctxt = mhi_cntrl->mhi_ctxt->er_ctxt; >> + for (i = 0; i < mhi_cntrl->total_ev_rings; i++, er_ctxt++, >> + mhi_event++) { >> + struct mhi_ring *ring = &mhi_event->ring; >> + >> + /* Skip offload events */ >> + if (mhi_event->offload_ev) >> + continue; >> + >> + ring->rp = ring->base; >> + ring->wp = ring->base; >> + er_ctxt->rp = er_ctxt->rbase; >> + er_ctxt->wp = er_ctxt->rbase; >> + } >> + >> + mhi_ready_state_transition(mhi_cntrl); >> + >> +exit_sys_error_transition: >> dev_dbg(dev, "Exiting with PM state: %s, MHI state: %s\n", >> to_mhi_pm_state_str(mhi_cntrl->pm_state), >> TO_MHI_STATE_STR(mhi_cntrl->dev_state)); >> @@ -666,8 +782,7 @@ void mhi_pm_st_worker(struct work_struct *work) >> mhi_ready_state_transition(mhi_cntrl); >> break; >> case DEV_ST_TRANSITION_SYS_ERR: >> - mhi_pm_disable_transition >> - (mhi_cntrl, MHI_PM_SYS_ERR_PROCESS); >> + mhi_pm_sys_error_transition(mhi_cntrl); >> break; >> case DEV_ST_TRANSITION_DISABLE: >> mhi_pm_disable_transition >> -- >> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora >> Forum, >> a Linux Foundation Collaborative Project >> Thanks, Bhaumik -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Powered by blists - more mailing lists