> -----Original Message-----
> From: linux-scsi-ow...@vger.kernel.org [mailto:linux-scsi-
> ow...@vger.kernel.org] On Behalf Of Michal Potomski
> Sent: Thursday, November 09, 2017 11:17 AM
> To: linux-scsi@vger.kernel.org
> Cc: vinholika...@gmail.com; martin.peter...@oracle.com;
> j...@linux.vnet.ibm.com; subha...@codeaurora.org;
> szymonx.mielcza...@intel.com
> Subject: [PATCH] scsi: ufs: Fix Runtime PM
> 
> From: Michał Potomski <michalx.potom...@intel.com>
> 
> Recent testing of Runtime PM for UFS has shown it's not working as intended.
> To acheive fully working Runtime PM, first we have to put back scsi_device
> autopm reference counter.
> 
> Existing implementation was prone to races and not working for tranfsers to
> sleeping devices. 

Wouldn't calling  pm_runtime_mark_last_busy() just before 
pm_runtime_put_autosuspend() suffice?

This commit aims to fix this to acheive fully working
> environment. Due to runtime PM being previously disabled by not putting
> scsi_device autopm counter, the Runtime PM is set to be forbidden as
> default, to not cause problems with hosts and devices, which do not fully
> support different Device and Link states.
> 
> It can be still enabled through sysFS power/control attribute.
> 
> Signed-off-by: Michał Potomski <michalx.potom...@intel.com>
> ---
>  drivers/scsi/ufs/ufshcd-pci.c |  4 +++-
>  drivers/scsi/ufs/ufshcd.c     | 55 ++++++++++++++++++++++++++++++++++-------
> --
>  2 files changed, 47 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c 
> index
> 925b0ec7ec54..4fffb1123876 100644
> --- a/drivers/scsi/ufs/ufshcd-pci.c
> +++ b/drivers/scsi/ufs/ufshcd-pci.c
> @@ -184,8 +184,10 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct
> pci_device_id *id)
>       }
> 
>       pci_set_drvdata(pdev, hba);
> +     pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
> +     pm_runtime_use_autosuspend(&pdev->dev);
>       pm_runtime_put_noidle(&pdev->dev);
> -     pm_runtime_allow(&pdev->dev);
> +     pm_runtime_forbid(&pdev->dev);
> 
>       return 0;
>  }
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
> 011c3369082c..e7c7ed9bf8a5 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -240,6 +240,28 @@ static inline bool ufshcd_valid_tag(struct ufs_hba
> *hba, int tag)
>       return tag >= 0 && tag < hba->nutrs;
>  }
> 
> +static void ufshcd_pm_runtime_get(struct device *dev) {
> +     // Don't trigger PM events while in transition states
> +     if (dev->power.runtime_status == RPM_RESUMING ||
> +         dev->power.runtime_status == RPM_SUSPENDING)
> +             pm_runtime_get_noresume(dev);
> +     else
> +             pm_runtime_get_sync(dev);
> +}
> +
> +static void ufshcd_pm_runtime_put(struct device *dev) {
> +     pm_runtime_mark_last_busy(dev);
> +
> +     // Don't trigger PM events while in transition states
> +     if (dev->power.runtime_status == RPM_RESUMING ||
> +         dev->power.runtime_status == RPM_SUSPENDING)
> +             pm_runtime_put_noidle(dev);
> +     else
> +             pm_runtime_put_autosuspend(dev);
> +}
> +
>  static inline int ufshcd_enable_irq(struct ufs_hba *hba)  {
>       int ret = 0;
> @@ -1345,7 +1367,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct
> device *dev,
>       if (value == hba->clk_scaling.is_allowed)
>               goto out;
> 
> -     pm_runtime_get_sync(hba->dev);
> +     ufshcd_pm_runtime_get(hba->dev);
>       ufshcd_hold(hba, false);
> 
>       cancel_work_sync(&hba->clk_scaling.suspend_work);
> @@ -1364,7 +1386,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct
> device *dev,
>       }
> 
>       ufshcd_release(hba);
> -     pm_runtime_put_sync(hba->dev);
> +     ufshcd_pm_runtime_put(hba->dev);
>  out:
>       return count;
>  }
> @@ -1948,6 +1970,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct
> uic_command *uic_cmd)
>       unsigned long flags;
> 
>       ufshcd_hold(hba, false);
> +     ufshcd_pm_runtime_get(hba->dev);
>       mutex_lock(&hba->uic_cmd_mutex);
>       ufshcd_add_delay_before_dme_cmd(hba);
> 
> @@ -1959,6 +1982,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct
> uic_command *uic_cmd)
> 
>       mutex_unlock(&hba->uic_cmd_mutex);
> 
> +     ufshcd_pm_runtime_put(hba->dev);
>       ufshcd_release(hba);
>       return ret;
>  }
> @@ -2345,6 +2369,7 @@ static int ufshcd_queuecommand(struct Scsi_Host
> *host, struct scsi_cmnd *cmd)
>               clear_bit_unlock(tag, &hba->lrb_in_use);
>               goto out;
>       }
> +     ufshcd_pm_runtime_get(hba->dev);
>       WARN_ON(hba->clk_gating.state != CLKS_ON);
> 
>       lrbp = &hba->lrb[tag];
> @@ -3555,6 +3580,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba,
> struct uic_command *cmd)
>       int ret;
>       bool reenable_intr = false;
> 
> +     ufshcd_pm_runtime_get(hba->dev);
>       mutex_lock(&hba->uic_cmd_mutex);
>       init_completion(&uic_async_done);
>       ufshcd_add_delay_before_dme_cmd(hba);
> @@ -3609,6 +3635,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba,
> struct uic_command *cmd)
>               ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>       spin_unlock_irqrestore(hba->host->host_lock, flags);
>       mutex_unlock(&hba->uic_cmd_mutex);
> +     ufshcd_pm_runtime_put(hba->dev);
> 
>       return ret;
>  }
> @@ -4386,6 +4413,7 @@ static int ufshcd_slave_configure(struct scsi_device
> *sdev)
> 
>       blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
>       blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX);
> +     scsi_autopm_put_device(sdev);
> 
>       return 0;
>  }
> @@ -4622,6 +4650,7 @@ static void __ufshcd_transfer_req_compl(struct
> ufs_hba *hba,
>                       /* Do not touch lrbp after scsi done */
>                       cmd->scsi_done(cmd);
>                       __ufshcd_release(hba);
> +                     ufshcd_pm_runtime_put(hba->dev);
>               } else if (lrbp->command_type ==
> UTP_CMD_TYPE_DEV_MANAGE ||
>                       lrbp->command_type ==
> UTP_CMD_TYPE_UFS_STORAGE) {
>                       if (hba->dev_cmd.complete) {
> @@ -4951,7 +4980,7 @@ static void ufshcd_exception_event_handler(struct
> work_struct *work)
>       u32 status = 0;
>       hba = container_of(work, struct ufs_hba, eeh_work);
> 
> -     pm_runtime_get_sync(hba->dev);
> +     ufshcd_pm_runtime_get(hba->dev);
>       err = ufshcd_get_ee_status(hba, &status);
>       if (err) {
>               dev_err(hba->dev, "%s: failed to get exception status %d\n",
> @@ -4965,7 +4994,7 @@ static void ufshcd_exception_event_handler(struct
> work_struct *work)
>               ufshcd_bkops_exception_event_handler(hba);
> 
>  out:
> -     pm_runtime_put_sync(hba->dev);
> +     ufshcd_pm_runtime_put(hba->dev);
>       return;
>  }
> 
> @@ -5065,7 +5094,7 @@ static void ufshcd_err_handler(struct work_struct
> *work)
> 
>       hba = container_of(work, struct ufs_hba, eh_work);
> 
> -     pm_runtime_get_sync(hba->dev);
> +     ufshcd_pm_runtime_get(hba->dev);
>       ufshcd_hold(hba, false);
> 
>       spin_lock_irqsave(hba->host->host_lock, flags); @@ -5177,7 +5206,7
> @@ static void ufshcd_err_handler(struct work_struct *work)
>       spin_unlock_irqrestore(hba->host->host_lock, flags);
>       scsi_unblock_requests(hba->host);
>       ufshcd_release(hba);
> -     pm_runtime_put_sync(hba->dev);
> +     ufshcd_pm_runtime_put(hba->dev);
>  }
> 
>  static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist,
> @@ -6425,7 +6454,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
>               }
> 
>               scsi_scan_host(hba->host);
> -             pm_runtime_put_sync(hba->dev);
> +             ufshcd_pm_runtime_put(hba->dev);
>       }
> 
>       if (!hba->is_init_prefetch)
> @@ -6437,7 +6466,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
>        * present, turn off the power/clocks etc.
>        */
>       if (ret && !ufshcd_eh_in_progress(hba) && !hba-
> >pm_op_in_progress) {
> -             pm_runtime_put_sync(hba->dev);
> +             ufshcd_pm_runtime_put(hba->dev);
>               ufshcd_hba_exit(hba);
>       }
> 
> @@ -7747,6 +7776,8 @@ EXPORT_SYMBOL(ufshcd_shutdown);  void
> ufshcd_remove(struct ufs_hba *hba)  {
>       ufshcd_remove_sysfs_nodes(hba);
> +     // Resume if suspended for sync
> +     ufshcd_pm_runtime_get(hba->dev);
>       scsi_remove_host(hba->host);
>       /* disable interrupts */
>       ufshcd_disable_intr(hba, hba->intr_mask); @@ -7756,6 +7787,8 @@
> void ufshcd_remove(struct ufs_hba *hba)
>       if (ufshcd_is_clkscaling_supported(hba))
>               device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
>       ufshcd_hba_exit(hba);
> +     // Final sync finished - put it back
> +     ufshcd_pm_runtime_put(hba->dev);
>  }
>  EXPORT_SYMBOL_GPL(ufshcd_remove);
> 
> @@ -7978,11 +8011,11 @@ int ufshcd_init(struct ufs_hba *hba, void
> __iomem *mmio_base, unsigned int irq)
>                                               UFS_SLEEP_PWR_MODE,
>                                               UIC_LINK_HIBERN8_STATE);
>       hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
> -                                             UFS_SLEEP_PWR_MODE,
> -                                             UIC_LINK_HIBERN8_STATE);
> +
>       UFS_POWERDOWN_PWR_MODE,
> +                                             UIC_LINK_OFF_STATE);
> 
>       /* Hold auto suspend until async scan completes */
> -     pm_runtime_get_sync(dev);
> +     ufshcd_pm_runtime_get(dev);
> 
>       /*
>        * We are assuming that device wasn't put in sleep/power-down
> --
> 2.13.0.67.g10c78a1
> 
> --------------------------------------------------------------------
> 
> Intel Technology Poland sp. z o.o.
> ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII
> Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-
> 07-52-316 | Kapital zakladowy 200.000 PLN.
> 
> Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata
> i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej
> wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie;
> jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
> This e-mail and any attachments may contain confidential material for the
> sole use of the intended recipient(s). If you are not the intended recipient,
> please contact the sender and delete all copies; any review or distribution by
> others is strictly prohibited.

Reply via email to