RE: [RFC PATCH v2 3/3] scsi: ufs: add vendor specific write booster To support the fuction of writebooster by vendor. The WB behavior that the vendor wants is slightly different. But we have to support it

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit log please.
Looks like your log slips into your title.

Thanks,
Avri
> 
> 
> Signed-off-by: SEO HOYOUNG <hy50.seo@xxxxxxxxxxx>
> ---
>  drivers/scsi/ufs/Makefile     |   1 +
>  drivers/scsi/ufs/ufs-exynos.c |   6 +
>  drivers/scsi/ufs/ufs_ctmwb.c  | 279 ++++++++++++++++++++++++++++++++++
>  drivers/scsi/ufs/ufs_ctmwb.h  |  27 ++++
>  4 files changed, 313 insertions(+)
>  create mode 100644 drivers/scsi/ufs/ufs_ctmwb.c
>  create mode 100644 drivers/scsi/ufs/ufs_ctmwb.h
> 
> diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
> index 9810963bc049..b1ba36c7d66f 100644
> --- a/drivers/scsi/ufs/Makefile
> +++ b/drivers/scsi/ufs/Makefile
> @@ -5,6 +5,7 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-
> g210-pltfrm.o ufshcd-dwc.o tc-d
>  obj-$(CONFIG_SCSI_UFS_CDNS_PLATFORM) += cdns-pltfrm.o
>  obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
>  obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o
> +obj-$(CONFIG_SCSI_UFS_VENDOR_WB) += ufs_ctmwb.o
>  obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
>  ufshcd-core-y                          += ufshcd.o ufs-sysfs.o
>  ufshcd-core-$(CONFIG_SCSI_UFS_BSG)     += ufs_bsg.o
> diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
> index 32b61ba77241..f127f5f2bf36 100644
> --- a/drivers/scsi/ufs/ufs-exynos.c
> +++ b/drivers/scsi/ufs/ufs-exynos.c
> @@ -22,6 +22,9 @@
> 
>  #include "ufs-exynos.h"
> 
> +#ifdef CONFIG_SCSI_UFS_VENDOR_WB
> +#include "ufs_ctmwb.h"
> +#endif
>  /*
>   * Exynos's Vendor specific registers for UFSHCI
>   */
> @@ -989,6 +992,9 @@ static int exynos_ufs_init(struct ufs_hba *hba)
>                 goto phy_off;
> 
>         ufs->hba = hba;
> +#ifdef CONFIG_SCSI_UFS_VENDOR_WB
> +       ufs->hba->wb_ops = ufshcd_ctmwb_init();
> +#endif
>         ufs->opts = ufs->drv_data->opts;
>         ufs->rx_sel_idx = PA_MAXDATALANES;
>         if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX)
> diff --git a/drivers/scsi/ufs/ufs_ctmwb.c b/drivers/scsi/ufs/ufs_ctmwb.c
> new file mode 100644
> index 000000000000..ab39f40721ae
> --- /dev/null
> +++ b/drivers/scsi/ufs/ufs_ctmwb.c
> @@ -0,0 +1,279 @@
> +#include "ufshcd.h"
> +#include "ufshci.h"
> +#include "ufs_ctmwb.h"
> +
> +static struct ufshba_ctmwb hba_ctmwb;
> +
> +/* Query request retries */
> +#define QUERY_REQ_RETRIES 3
> +
> +static int ufshcd_query_attr_retry(struct ufs_hba *hba,
> +       enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector,
> +       u32 *attr_val)
> +{
> +       int ret = 0;
> +       u32 retries;
> +
> +        for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
> +               ret = ufshcd_query_attr(hba, opcode, idn, index,
> +                                               selector, attr_val);
> +               if (ret)
> +                       dev_dbg(hba->dev, "%s: failed with error %d, retries %d\n",
> +                               __func__, ret, retries);
> +               else
> +                       break;
> +       }
> +
> +       if (ret)
> +               dev_err(hba->dev,
> +                       "%s: query attribute, idn %d, failed with error %d after %d
> retires\n",
> +                       __func__, idn, ret, QUERY_REQ_RETRIES);
> +       return ret;
> +}
> +
> +static int ufshcd_query_flag_retry(struct ufs_hba *hba,
> +       enum query_opcode opcode, enum flag_idn idn, bool *flag_res)
> +{
> +       int ret;
> +       int retries;
> +
> +       for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
> +               ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
> +               if (ret)
> +                       dev_dbg(hba->dev,
> +                               "%s: failed with error %d, retries %d\n",
> +                               __func__, ret, retries);
> +               else
> +                       break;
> +       }
> +
> +       if (ret)
> +               dev_err(hba->dev,
> +                       "%s: query attribute, opcode %d, idn %d, failed with error %d
> after %d retries\n",
> +                       __func__, (int)opcode, (int)idn, ret, retries);
> +       return ret;
> +}
> +
> +static int ufshcd_reset_ctmwb(struct ufs_hba *hba, bool force)
> +{
> +       int err = 0;
> +
> +       if (!hba_ctmwb.support_ctmwb)
> +               return 0;
> +
> +       if (ufshcd_is_ctmwb_off(hba_ctmwb)) {
> +               dev_info(hba->dev, "%s: turbo write already disabled. ctmwb_state
> = %d\n",
> +                       __func__, hba_ctmwb.ufs_ctmwb_state);
> +               return 0;
> +       }
> +
> +       if (ufshcd_is_ctmwb_err(hba_ctmwb))
> +               dev_err(hba->dev, "%s: previous turbo write control was failed.\n",
> +                       __func__);
> +
> +       if (force)
> +               err = ufshcd_query_flag_retry(hba,
> UPIU_QUERY_OPCODE_CLEAR_FLAG,
> +                               QUERY_FLAG_IDN_WB_EN, NULL);
> +
> +       if (err) {
> +               ufshcd_set_ctmwb_err(hba_ctmwb);
> +               dev_err(hba->dev, "%s: disable turbo write failed. err = %d\n",
> +                       __func__, err);
> +       } else {
> +               ufshcd_set_ctmwb_off(hba_ctmwb);
> +               dev_info(hba->dev, "%s: ufs turbo write disabled \n", __func__);
> +       }
> +
> +       return 0;
> +}
> +
> +static int ufshcd_get_ctmwb_buf_status(struct ufs_hba *hba, u32 *status)
> +{
> +       return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
> +                       QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, status);
> +}
> +
> +static int ufshcd_ctmwb_manual_flush_ctrl(struct ufs_hba *hba, int en)
> +{
> +       int err = 0;
> +
> +       dev_info(hba->dev, "%s: %sable turbo write manual flush\n",
> +                               __func__, en ? "en" : "dis");
> +       if (en) {
> +               err = ufshcd_query_flag_retry(hba,
> UPIU_QUERY_OPCODE_SET_FLAG,
> +                                       QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, NULL);
> +               if (err)
> +                       dev_err(hba->dev, "%s: enable turbo write failed. err = %d\n",
> +                               __func__, err);
> +       } else {
> +               err = ufshcd_query_flag_retry(hba,
> UPIU_QUERY_OPCODE_CLEAR_FLAG,
> +                                       QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, NULL);
> +               if (err)
> +                       dev_err(hba->dev, "%s: disable turbo write failed. err = %d\n",
> +                               __func__, err);
> +       }
> +
> +       return err;
> +}
> +
> +static int ufshcd_ctmwb_flush_ctrl(struct ufs_hba *hba)
> +{
> +       int err = 0;
> +       u32 curr_status = 0;
> +
> +       err = ufshcd_get_ctmwb_buf_status(hba, &curr_status);
> +
> +       if (!err && (curr_status <= UFS_WB_MANUAL_FLUSH_THRESHOLD)) {
> +               dev_info(hba->dev, "%s: enable ctmwb manual flush, buf status :
> %d\n",
> +                               __func__, curr_status);
> +               scsi_block_requests(hba->host);
> +               err = ufshcd_ctmwb_manual_flush_ctrl(hba, 1);
> +               if (!err) {
> +                       mdelay(100);
> +                       err = ufshcd_ctmwb_manual_flush_ctrl(hba, 0);
> +                       if (err)
> +                               dev_err(hba->dev, "%s: disable ctmwb manual flush failed.
> err = %d\n",
> +                                               __func__, err);
> +               } else
> +                       dev_err(hba->dev, "%s: enable ctmwb manual flush failed. err =
> %d\n",
> +                                       __func__, err);
> +               scsi_unblock_requests(hba->host);
> +       }
> +       return err;
> +}
> +
> +static int ufshcd_ctmwb_ctrl(struct ufs_hba *hba, bool enable)
> +{
> +       int err;
> +#if 0
> +       if (!hba->support_ctmwb)
> +               return;
> +
> +       if (hba->pm_op_in_progress) {
> +               dev_err(hba->dev, "%s: ctmwb ctrl during pm operation is not
> allowed.\n",
> +                       __func__);
> +               return;
> +       }
> +
> +       if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
> +               dev_err(hba->dev, "%s: ufs host is not available.\n",
> +                       __func__);
> +               return;
> +       }
> +       if (ufshcd_is_ctmwb_err(hba_ctmwb))
> +               dev_err(hba->dev, "%s: previous turbo write control was failed.\n",
> +                       __func__);
> +#endif
> +       if (enable) {
> +               if (ufshcd_is_ctmwb_on(hba_ctmwb)) {
> +                       dev_err(hba->dev, "%s: turbo write already enabled.
> ctmwb_state = %d\n",
> +                               __func__, hba_ctmwb.ufs_ctmwb_state);
> +                       return 0;
> +               }
> +               pm_runtime_get_sync(hba->dev);
> +               err = ufshcd_query_flag_retry(hba,
> UPIU_QUERY_OPCODE_SET_FLAG,
> +                                       QUERY_FLAG_IDN_WB_EN, NULL);
> +               if (err) {
> +                       ufshcd_set_ctmwb_err(hba_ctmwb);
> +                       dev_err(hba->dev, "%s: enable turbo write failed. err = %d\n",
> +                               __func__, err);
> +               } else {
> +                       ufshcd_set_ctmwb_on(hba_ctmwb);
> +                       dev_info(hba->dev, "%s: ufs turbo write enabled \n",
> __func__);
> +               }
> +       } else {
> +               if (ufshcd_is_ctmwb_off(hba_ctmwb)) {
> +                       dev_err(hba->dev, "%s: turbo write already disabled.
> ctmwb_state = %d\n",
> +                               __func__, hba_ctmwb.ufs_ctmwb_state);
> +                       return 0;
> +               }
> +               pm_runtime_get_sync(hba->dev);
> +               err = ufshcd_query_flag_retry(hba,
> UPIU_QUERY_OPCODE_CLEAR_FLAG,
> +                                       QUERY_FLAG_IDN_WB_EN, NULL);
> +               if (err) {
> +                       ufshcd_set_ctmwb_err(hba_ctmwb);
> +                       dev_err(hba->dev, "%s: disable turbo write failed. err = %d\n",
> +                               __func__, err);
> +               } else {
> +                       ufshcd_set_ctmwb_off(hba_ctmwb);
> +                       dev_info(hba->dev, "%s: ufs turbo write disabled \n",
> __func__);
> +               }
> +       }
> +
> +       pm_runtime_put_sync(hba->dev);
> +
> +       return 0;
> +}
> +
> +/**
> + * ufshcd_get_ctmwbbuf_unit - get ctmwb buffer alloc units
> + * @sdev: pointer to SCSI device
> + *
> + * Read dLUNumTurboWriteBufferAllocUnits in UNIT Descriptor
> + * to check if LU supports turbo write feature
> + */
> +static int ufshcd_get_ctmwbbuf_unit(struct ufs_hba *hba)
> +{
> +       struct scsi_device *sdev = hba->sdev_ufs_device;
> +       struct ufshba_ctmwb *hba_ctmwb = (struct ufshba_ctmwb *)hba-
> >wb_ops;
> +       int ret = 0;
> +
> +       u32 dLUNumTurboWriteBufferAllocUnits = 0;
> +       u8 desc_buf[4];
> +
> +       if (!hba_ctmwb->support_ctmwb)
> +               return 0;
> +
> +       ret = ufshcd_read_unit_desc_param(hba,
> +                       ufshcd_scsi_to_upiu_lun(sdev->lun),
> +                       UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS,
> +                       desc_buf,
> +                       sizeof(dLUNumTurboWriteBufferAllocUnits));
> +
> +       /* Some WLUN doesn't support unit descriptor */
> +       if ((ret == -EOPNOTSUPP) || scsi_is_wlun(sdev->lun)){
> +               hba_ctmwb->support_ctmwb_lu = false;
> +               dev_info(hba->dev,"%s: do not support WB\n", __func__);
> +               return 0;
> +       }
> +
> +       dLUNumTurboWriteBufferAllocUnits = ((desc_buf[0] << 24)|
> +                       (desc_buf[1] << 16) |
> +                       (desc_buf[2] << 8) |
> +                       desc_buf[3]);
> +
> +       if (dLUNumTurboWriteBufferAllocUnits) {
> +               hba_ctmwb->support_ctmwb_lu = true;
> +               dev_info(hba->dev, "%s: LU %d supports ctmwb, ctmwbbuf unit :
> 0x%x\n",
> +                               __func__, (int)sdev->lun,
> dLUNumTurboWriteBufferAllocUnits);
> +       } else
> +               hba_ctmwb->support_ctmwb_lu = false;
> +
> +       return 0;
> +}
> +
> +static inline int ufshcd_ctmwb_toggle_flush(struct ufs_hba *hba, enum
> ufs_pm_op pm_op)
> +{
> +       ufshcd_ctmwb_flush_ctrl(hba);
> +
> +       if (ufshcd_is_system_pm(pm_op))
> +               ufshcd_reset_ctmwb(hba, true);
> +
> +       return 0;
> +}
> +
> +static struct ufs_wb_ops exynos_ctmwb_ops = {
> +       .wb_toggle_flush_vendor = ufshcd_ctmwb_toggle_flush,
> +       .wb_alloc_units_vendor = ufshcd_get_ctmwbbuf_unit,
> +       .wb_ctrl_vendor = ufshcd_ctmwb_ctrl,
> +       .wb_reset_vendor = ufshcd_reset_ctmwb,
> +};
> +
> +struct ufs_wb_ops *ufshcd_ctmwb_init(void)
> +{
> +       hba_ctmwb.support_ctmwb = 1;
> +
> +       return &exynos_ctmwb_ops;
> +}
> +EXPORT_SYMBOL_GPL(ufshcd_ctmwb_init);
> +
> diff --git a/drivers/scsi/ufs/ufs_ctmwb.h b/drivers/scsi/ufs/ufs_ctmwb.h
> new file mode 100644
> index 000000000000..073e21a4900b
> --- /dev/null
> +++ b/drivers/scsi/ufs/ufs_ctmwb.h
> @@ -0,0 +1,27 @@
> +#ifndef _UFS_CTMWB_H_
> +#define _UFS_CTMWB_H_
> +
> +enum ufs_ctmwb_state {
> +       UFS_WB_OFF_STATE        = 0,    /* turbo write disabled state */
> +       UFS_WB_ON_STATE = 1,            /* turbo write enabled state */
> +       UFS_WB_ERR_STATE        = 2,            /* turbo write error state */
> +};
> +
> +#define ufshcd_is_ctmwb_off(hba) ((hba).ufs_ctmwb_state ==
> UFS_WB_OFF_STATE)
> +#define ufshcd_is_ctmwb_on(hba) ((hba).ufs_ctmwb_state ==
> UFS_WB_ON_STATE)
> +#define ufshcd_is_ctmwb_err(hba) ((hba).ufs_ctmwb_state ==
> UFS_WB_ERR_STATE)
> +#define ufshcd_set_ctmwb_off(hba) ((hba).ufs_ctmwb_state =
> UFS_WB_OFF_STATE)
> +#define ufshcd_set_ctmwb_on(hba) ((hba).ufs_ctmwb_state =
> UFS_WB_ON_STATE)
> +#define ufshcd_set_ctmwb_err(hba) ((hba).ufs_ctmwb_state =
> UFS_WB_ERR_STATE)
> +
> +#define UFS_WB_MANUAL_FLUSH_THRESHOLD  5
> +
> +struct ufshba_ctmwb {
> +       enum ufs_ctmwb_state ufs_ctmwb_state;
> +       bool support_ctmwb;
> +
> +       bool support_ctmwb_lu;
> +};
> +
> +struct ufs_wb_ops *ufshcd_ctmwb_init(void);
> +#endif
> --
> 2.26.0





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux