From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from omzsmtpe01.verizonbusiness.com ([199.249.25.210]:63682 "EHLO omzsmtpe01.verizonbusiness.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754451AbdDDTdC (ORCPT ); Tue, 4 Apr 2017 15:33:02 -0400 From: alexander.levin@verizon.com To: "gregkh@linuxfoundation.org" CC: "stable@vger.kernel.org" Subject: [PATCH for 4.9 30/98] scsi: ufs: add quirk to increase host PA_SaveConfigTime Date: Tue, 4 Apr 2017 19:32:13 +0000 Message-ID: <20170404193158.19041-31-alexander.levin@verizon.com> References: <20170404193158.19041-1-alexander.levin@verizon.com> In-Reply-To: <20170404193158.19041-1-alexander.levin@verizon.com> Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org List-ID: From: Subhash Jadavani [ Upstream commit 56d4a1866d748732fd8d690b2c2156bbc9c9eb02 ] The maximum value PA_SaveConfigTime is 250 (10us) but this is not enough for some vendors. Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime. Gear switch can be issued by host controller as an error recovery and any software delay will not help on this case so we need to increase PA_SaveConfigTime to >32us as per vendor recommendation. This change adds a quirk to increase the PA_SaveConfigTime parameter. Reviewed-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/ufs/ufs-qcom.c | 30 ++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-qcom.h | 1 + drivers/scsi/ufs/ufs_quirks.h | 30 +++++++++--------------------- drivers/scsi/ufs/ufshcd.c | 26 ++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 9 +++++++++ 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 3aedf73..462bf42 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -23,6 +23,7 @@ #include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" +#include "ufs_quirks.h" #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) =20 @@ -1031,6 +1032,34 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba= *hba, return ret; } =20 +static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba) +{ + int err; + u32 pa_vs_config_reg1; + + err =3D ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), + &pa_vs_config_reg1); + if (err) + goto out; + + /* Allow extension of MSB bits of PA_SaveConfigTime attribute */ + err =3D ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), + (pa_vs_config_reg1 | (1 << 12))); + +out: + return err; +} + +static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) +{ + int err =3D 0; + + if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) + err =3D ufs_qcom_quirk_host_pa_saveconfigtime(hba); + + return err; +} + static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { struct ufs_qcom_host *host =3D ufshcd_get_variant(hba); @@ -1616,6 +1645,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = =3D { .hce_enable_notify =3D ufs_qcom_hce_enable_notify, .link_startup_notify =3D ufs_qcom_link_startup_notify, .pwr_change_notify =3D ufs_qcom_pwr_change_notify, + .apply_dev_quirks =3D ufs_qcom_apply_dev_quirks, .suspend =3D ufs_qcom_suspend, .resume =3D ufs_qcom_resume, .dbg_register_dump =3D ufs_qcom_dump_dbg_regs, diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a19307a..fe517cd 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type { UFS_QCOM_DBG_PRINT_TEST_BUS_EN) =20 /* QUniPro Vendor specific attributes */ +#define PA_VS_CONFIG_REG1 0x9000 #define DME_VS_CORE_CLK_CTRL 0xD002 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index f798305..08b799d 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -134,29 +134,17 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) =20 +/* + * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough f= or + * some vendors. + * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTi= me. + * Gear switch can be issued by host controller as an error recovery and a= ny + * software delay will not help on this case so we need to increase + * PA_SaveConfigTime to >32us as per vendor recommendation. + */ +#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) =20 struct ufs_hba; void ufs_advertise_fixup_device(struct ufs_hba *hba); =20 -static struct ufs_dev_fix ufs_fixups[] =3D { - /* UFS cards deviations table */ - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_NO_FASTAUTO), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), - UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", - UFS_DEVICE_QUIRK_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", - UFS_DEVICE_QUIRK_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), - - END_FIX -}; #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 6f6a209..6c75f2a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -188,6 +188,30 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl= ) return ufs_pm_lvl_states[lvl].link_state; } =20 +static struct ufs_dev_fix ufs_fixups[] =3D { + /* UFS cards deviations table */ + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_NO_FASTAUTO), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), + UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", + UFS_DEVICE_QUIRK_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", + UFS_DEVICE_QUIRK_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), + + END_FIX +}; + static void ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); @@ -5062,6 +5086,8 @@ static void ufshcd_tune_unipro_params(struct ufs_hba = *hba) =20 if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) ufshcd_quirk_tune_host_pa_tactivate(hba); + + ufshcd_vops_apply_dev_quirks(hba); } =20 /** diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 5b65441..0450982 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -261,6 +261,7 @@ struct ufs_pwr_mode_info { * @pwr_change_notify: called before and after a power mode change * is carried out to allow vendor spesific capabilities * to be set. + * @apply_dev_quirks: called to apply device specific quirks * @suspend: called during host controller PM callback * @resume: called during host controller PM callback * @dbg_register_dump: used to dump controller debug information @@ -283,6 +284,7 @@ struct ufs_hba_variant_ops { enum ufs_notify_change_status status, struct ufs_pa_layer_attr *, struct ufs_pa_layer_attr *); + int (*apply_dev_quirks)(struct ufs_hba *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); void (*dbg_register_dump)(struct ufs_hba *hba); @@ -805,6 +807,13 @@ static inline int ufshcd_vops_pwr_change_notify(struct= ufs_hba *hba, return -ENOTSUPP; } =20 +static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->apply_dev_quirks) + return hba->vops->apply_dev_quirks(hba); + return 0; +} + static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op = op) { if (hba->vops && hba->vops->suspend) --=20 2.9.3