diff mbox series

[v5,1/8] scsi: ufs: enable WriteBooster on some pre-3.1 UFS devices

Message ID 20200503113415.21034-2-stanley.chu@mediatek.com (mailing list archive)
State New, archived
Headers show
Series scsi: ufs: support LU Dedicated buffer mode for WriteBooster | expand

Commit Message

Stanley Chu May 3, 2020, 11:34 a.m. UTC
WriteBooster feature can be supported by some pre-3.1 UFS devices
by upgrading firmware.

To enable WriteBooster feature in such devices, introduce a device
quirk to relax the entrance condition of ufshcd_wb_probe() to allow
host driver to check those devices' WriteBooster capability.

WriteBooster feature can be available if below all conditions are
satisfied,

1. Host enables WriteBooster capability
2. UFS 3.1 device or UFS pre-3.1 device with quirk
   UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES enabled
3. Device descriptor has dExtendedUFSFeaturesSupport field
4. WriteBooster support is specified in above field

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufs_quirks.h |  7 ++++
 drivers/scsi/ufs/ufshcd.c     | 67 ++++++++++++++++++++++-------------
 2 files changed, 49 insertions(+), 25 deletions(-)

Comments

Avri Altman May 4, 2020, 10:37 a.m. UTC | #1
> 
>  static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
>  {
> +       if (!ufshcd_is_wb_allowed(hba))
> +               return;
> +
> +       if (hba->desc_size.dev_desc <=
> DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP)
Should be 
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4 

> +               goto wb_disabled;
> +
>         hba->dev_info.d_ext_ufs_feature_sup =
>                 get_unaligned_be32(desc_buf +
>                                    DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);


> 
>  static int ufs_get_device_desc(struct ufs_hba *hba)
> @@ -6862,10 +6890,6 @@ static int ufs_get_device_desc(struct ufs_hba
> *hba)
> 
>         model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
> 
> -       /* Enable WB only for UFS-3.1 */
> -       if (dev_info->wspecversion >= 0x310)
> -               ufshcd_wb_probe(hba, desc_buf);
> -
>         err = ufshcd_read_string_desc(hba, model_index,
>                                       &dev_info->model, SD_ASCII_STD);
>         if (err < 0) {
> @@ -6874,6 +6898,16 @@ static int ufs_get_device_desc(struct ufs_hba
> *hba)
>                 goto out;
>         }
> 
> +       ufs_fixup_device_setup(hba);
I don't think you should "hide" ufs_fixup_device_setup inside ufs_get_device_desc.

Thanks,
Avri
Stanley Chu May 4, 2020, 2:33 p.m. UTC | #2
Hi Avri,

On Mon, 2020-05-04 at 10:37 +0000, Avri Altman wrote:
> > 
> >  static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
> >  {
> > +       if (!ufshcd_is_wb_allowed(hba))
> > +               return;
> > +
> > +       if (hba->desc_size.dev_desc <=
> > DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP)
> Should be 
> DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4 

I think this description length check is redundant because the device
quirk shall be added only after WriteBooster supportat is confirmed in
attached UFS device. So I will remove this in next version.

> 
> > +               goto wb_disabled;
> > +
> >         hba->dev_info.d_ext_ufs_feature_sup =
> >                 get_unaligned_be32(desc_buf +
> >                                    DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
> 
> 
> > 
> >  static int ufs_get_device_desc(struct ufs_hba *hba)
> > @@ -6862,10 +6890,6 @@ static int ufs_get_device_desc(struct ufs_hba
> > *hba)
> > 
> >         model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
> > 
> > -       /* Enable WB only for UFS-3.1 */
> > -       if (dev_info->wspecversion >= 0x310)
> > -               ufshcd_wb_probe(hba, desc_buf);
> > -
> >         err = ufshcd_read_string_desc(hba, model_index,
> >                                       &dev_info->model, SD_ASCII_STD);
> >         if (err < 0) {
> > @@ -6874,6 +6898,16 @@ static int ufs_get_device_desc(struct ufs_hba
> > *hba)
> >                 goto out;
> >         }
> > 
> > +       ufs_fixup_device_setup(hba);
> I don't think you should "hide" ufs_fixup_device_setup inside ufs_get_device_desc.

The reason is as below,

ufshcd_wb_probe() needs the contents of Device Descriptor for
initialization. To avoid double reading the Device Descriptor, I keep
ufshcd_wb_probe() inside ufs_get_device_desc() to use its "desc_buf".

And ufshcd_wb_probe() needs well-configured device quirk for entrance
check, thus ufs_fixup_device_setup() shall be moved before
ufshcd_wb_probe().

This change does not affect the behavior and functionality of
ufs_fixup_device_setup() since it is still executed once only during
ufshcd_init() flow and not be executed again in the future.

Thanks,
Stanley Chu

> 
> Thanks,
> Avri
> 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
Stanley Chu May 7, 2020, 11:50 p.m. UTC | #3
Hi Avri,
On Mon, 2020-05-04 at 22:33 +0800, Stanley Chu wrote:
> Hi Avri,
> 
> On Mon, 2020-05-04 at 10:37 +0000, Avri Altman wrote:
> > > 
> > >  static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
> > >  {
> > > +       if (!ufshcd_is_wb_allowed(hba))
> > > +               return;
> > > +
> > > +       if (hba->desc_size.dev_desc <=
> > > DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP)
> > Should be 
> > DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4 
> 
> I think this description length check is redundant because the device
> quirk shall be added only after WriteBooster supportat is confirmed in
> attached UFS device. So I will remove this in next version.

Sorry this statement is incorrect because this kind on devices may have
short (without DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP field) before
firmware upgrading. So the checking for descriptor length is still
required to avoid out-of-boundary access in below codes.

I will add it back in next version and also fix the length.

Thanks,
Stanley Chu

> > 
> > _______________________________________________
> > Linux-mediatek mailing list
> > Linux-mediatek@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-mediatek
>
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index df7a1e6805a3..e3175a63c676 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -101,4 +101,11 @@  struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME	(1 << 9)
 
+/*
+ * Some pre-3.1 UFS devices can support extended features by upgrading
+ * the firmware. Enable this quirk to make UFS core driver probe and enable
+ * supported features on such devices.
+ */
+#define UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES (1 << 10)
+
 #endif /* UFS_QUIRKS_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 915e963398c4..04ddfb15e858 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6800,9 +6800,19 @@  static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
 
 static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
 {
+	if (!ufshcd_is_wb_allowed(hba))
+		return;
+
+	if (hba->desc_size.dev_desc <= DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP)
+		goto wb_disabled;
+
 	hba->dev_info.d_ext_ufs_feature_sup =
 		get_unaligned_be32(desc_buf +
 				   DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+
+	if (!(hba->dev_info.d_ext_ufs_feature_sup & UFS_DEV_WRITE_BOOSTER_SUP))
+		goto wb_disabled;
+
 	/*
 	 * WB may be supported but not configured while provisioning.
 	 * The spec says, in dedicated wb buffer mode,
@@ -6818,11 +6828,29 @@  static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
 	hba->dev_info.b_presrv_uspc_en =
 		desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN];
 
-	if (!((hba->dev_info.d_ext_ufs_feature_sup &
-		 UFS_DEV_WRITE_BOOSTER_SUP) &&
-		hba->dev_info.b_wb_buffer_type &&
+	if (!(hba->dev_info.b_wb_buffer_type &&
 	      hba->dev_info.d_wb_alloc_units))
-		hba->caps &= ~UFSHCD_CAP_WB_EN;
+		goto wb_disabled;
+
+	return;
+
+wb_disabled:
+	hba->caps &= ~UFSHCD_CAP_WB_EN;
+}
+
+static void ufs_fixup_device_setup(struct ufs_hba *hba)
+{
+	struct ufs_dev_fix *f;
+	struct ufs_dev_info *dev_info = &hba->dev_info;
+
+	for (f = ufs_fixups; f->quirk; f++) {
+		if ((f->wmanufacturerid == dev_info->wmanufacturerid ||
+		     f->wmanufacturerid == UFS_ANY_VENDOR) &&
+		     ((dev_info->model &&
+		       STR_PRFX_EQUAL(f->model, dev_info->model)) ||
+		      !strcmp(f->model, UFS_ANY_MODEL)))
+			hba->dev_quirks |= f->quirk;
+	}
 }
 
 static int ufs_get_device_desc(struct ufs_hba *hba)
@@ -6862,10 +6890,6 @@  static int ufs_get_device_desc(struct ufs_hba *hba)
 
 	model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
 
-	/* Enable WB only for UFS-3.1 */
-	if (dev_info->wspecversion >= 0x310)
-		ufshcd_wb_probe(hba, desc_buf);
-
 	err = ufshcd_read_string_desc(hba, model_index,
 				      &dev_info->model, SD_ASCII_STD);
 	if (err < 0) {
@@ -6874,6 +6898,16 @@  static int ufs_get_device_desc(struct ufs_hba *hba)
 		goto out;
 	}
 
+	ufs_fixup_device_setup(hba);
+
+	/*
+	 * Probe WB only for UFS-3.1 devices or UFS devices with quirk
+	 * UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES enabled
+	 */
+	if (dev_info->wspecversion >= 0x310 ||
+	    (hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES))
+		ufshcd_wb_probe(hba, desc_buf);
+
 	/*
 	 * ufshcd_read_string_desc returns size of the string
 	 * reset the error value
@@ -6893,21 +6927,6 @@  static void ufs_put_device_desc(struct ufs_hba *hba)
 	dev_info->model = NULL;
 }
 
-static void ufs_fixup_device_setup(struct ufs_hba *hba)
-{
-	struct ufs_dev_fix *f;
-	struct ufs_dev_info *dev_info = &hba->dev_info;
-
-	for (f = ufs_fixups; f->quirk; f++) {
-		if ((f->wmanufacturerid == dev_info->wmanufacturerid ||
-		     f->wmanufacturerid == UFS_ANY_VENDOR) &&
-		     ((dev_info->model &&
-		       STR_PRFX_EQUAL(f->model, dev_info->model)) ||
-		      !strcmp(f->model, UFS_ANY_MODEL)))
-			hba->dev_quirks |= f->quirk;
-	}
-}
-
 /**
  * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro
  * @hba: per-adapter instance
@@ -7244,8 +7263,6 @@  static int ufshcd_device_params_init(struct ufs_hba *hba)
 
 	ufshcd_get_ref_clk_gating_wait(hba);
 
-	ufs_fixup_device_setup(hba);
-
 	if (!ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
 			QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
 		hba->dev_info.f_power_on_wp_en = flag;