On Wed, Dec 08, 2021 at 02:27:35PM +0530, Manivannan Sadhasivam wrote: > From: Loic Poulain <loic.poulain@xxxxxxxxxx> > > For whatever reason, some devices like QCA6390, WCN6855 using ath11k > are not in M3 state during PM resume, but still functional. The > mhi_pm_resume should then not fail in those cases, and let the higher > level device specific stack continue resuming process. > > Add a new parameter to mhi_pm_resume, to force resuming, whatever the > current MHI state is. This fixes a regression with non functional > ath11k WiFi after suspend/resume cycle on some machines. > > Bug report: https://bugzilla.kernel.org/show_bug.cgi?id=214179 > > Fixes: 020d3b26c07a ("bus: mhi: Early MHI resume failure in non M3 state") > Cc: stable@xxxxxxxxxxxxxxx #5.13 > Link: https://lore.kernel.org/regressions/871r5p0x2u.fsf@xxxxxxxxxxxxxx/ > Reported-by: Kalle Valo <kvalo@xxxxxxxxxxxxxx> > Reported-by: Pengyu Ma <mapengyu@xxxxxxxxx> > Tested-by: Kalle Valo <kvalo@xxxxxxxxxx> > Acked-by: Kalle Valo <kvalo@xxxxxxxxxx> > Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx> > [mani: Added comment, bug report, reported-by tags and CCed stable] > Link: https://lore.kernel.org/r/20211206161059.107007-1-manivannan.sadhasivam@xxxxxxxxxx > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx> > --- > drivers/bus/mhi/core/pm.c | 10 +++++++--- > drivers/bus/mhi/pci_generic.c | 2 +- > drivers/net/wireless/ath/ath11k/mhi.c | 6 +++++- > include/linux/mhi.h | 3 ++- > 4 files changed, 15 insertions(+), 6 deletions(-) > > diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c > index fb99e3727155..8a486374d57a 100644 > --- a/drivers/bus/mhi/core/pm.c > +++ b/drivers/bus/mhi/core/pm.c > @@ -881,7 +881,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) > } > EXPORT_SYMBOL_GPL(mhi_pm_suspend); > > -int mhi_pm_resume(struct mhi_controller *mhi_cntrl) > +int mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force) > { > struct mhi_chan *itr, *tmp; > struct device *dev = &mhi_cntrl->mhi_dev->dev; > @@ -898,8 +898,12 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) > if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) > return -EIO; > > - if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) > - return -EINVAL; > + if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) { > + dev_warn(dev, "Resuming from non M3 state (%s)\n", > + TO_MHI_STATE_STR(mhi_get_mhi_state(mhi_cntrl))); > + if (!force) > + return -EINVAL; > + } > > /* Notify clients about exiting LPM */ > list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) { > diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c > index 4c577a731709..3394819e8115 100644 > --- a/drivers/bus/mhi/pci_generic.c > +++ b/drivers/bus/mhi/pci_generic.c > @@ -962,7 +962,7 @@ static int __maybe_unused mhi_pci_runtime_resume(struct device *dev) > return 0; /* Nothing to do at MHI level */ > > /* Exit M3, transition to M0 state */ > - err = mhi_pm_resume(mhi_cntrl); > + err = mhi_pm_resume(mhi_cntrl, false); > if (err) { > dev_err(&pdev->dev, "failed to resume device: %d\n", err); > goto err_recovery; > diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c > index 26c7ae242db6..f1f2fa2d690d 100644 > --- a/drivers/net/wireless/ath/ath11k/mhi.c > +++ b/drivers/net/wireless/ath/ath11k/mhi.c > @@ -533,7 +533,11 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, > ret = mhi_pm_suspend(ab_pci->mhi_ctrl); > break; > case ATH11K_MHI_RESUME: > - ret = mhi_pm_resume(ab_pci->mhi_ctrl); > + /* Do force MHI resume as some devices like QCA6390, WCN6855 > + * are not in M3 state but they are functional. So just ignore > + * the MHI state while resuming. > + */ > + ret = mhi_pm_resume(ab_pci->mhi_ctrl, true); > break; > case ATH11K_MHI_TRIGGER_RDDM: > ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); > diff --git a/include/linux/mhi.h b/include/linux/mhi.h > index 723985879035..102303288cee 100644 > --- a/include/linux/mhi.h > +++ b/include/linux/mhi.h > @@ -660,8 +660,9 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl); > /** > * mhi_pm_resume - Resume MHI from suspended state > * @mhi_cntrl: MHI controller > + * @force: Force resuming to M0 irrespective of the device MHI state > */ > -int mhi_pm_resume(struct mhi_controller *mhi_cntrl); > +int mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force); apis like this are horrid to work with over time. Why not just have: mhi_pm_resume_force() which then internally can set a flag that does this? That way the driver author does not have to stop every time they see this call and look up exactly what the true/false field means in the function call in their driver. It also lets you leave alone the existing calls to mhi_pm_suspend() that do not want to "force" anything. self-documenting code is good, this is not self-documenting at all. Also, is "force" really what you are doing here? This is a "normal" resume call, which should always work. The "force" option here really is just "ignore the current state of suspend for the device". So perhaps mhi_pm_resume_ignore_current_state() might be better? Or something shorter? Naming is hard, sorry. thanks, greg k-h