diff options
author | Subhash Jadavani <subhashj@codeaurora.org> | 2017-04-04 15:32:07 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-12 06:41:17 -0400 |
commit | 3a87bcdebf6eeb094be139a42626edb7dce8c960 (patch) | |
tree | f051cfc8311bc7c068a297552ab8af9ea418b26b | |
parent | d84be51d1c1d3fa148a3abdeeb1455690df59e63 (diff) |
scsi: ufs: ensure that host pa_tactivate is higher than device
[ Upstream commit c6a6db439868c7ba5cc90d4c461d9697ec731fa1 ]
Some UFS devices require host PA_TACTIVATE to be higher than
device PA_TACTIVATE otherwise it may get stuck during hibern8 sequence.
This change allows this by using quirk.
Reviewed-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/scsi/ufs/ufs_quirks.h | 9 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 73 | ||||
-rw-r--r-- | drivers/scsi/ufs/unipro.h | 4 |
3 files changed, 86 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 22f881e9253a..f7983058f3f7 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h | |||
@@ -128,6 +128,13 @@ struct ufs_dev_fix { | |||
128 | */ | 128 | */ |
129 | #define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM (1 << 6) | 129 | #define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM (1 << 6) |
130 | 130 | ||
131 | /* | ||
132 | * Some UFS devices require host PA_TACTIVATE to be lower than device | ||
133 | * PA_TACTIVATE, enabling this quirk ensure this. | ||
134 | */ | ||
135 | #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) | ||
136 | |||
137 | |||
131 | struct ufs_hba; | 138 | struct ufs_hba; |
132 | void ufs_advertise_fixup_device(struct ufs_hba *hba); | 139 | void ufs_advertise_fixup_device(struct ufs_hba *hba); |
133 | 140 | ||
@@ -140,6 +147,8 @@ static struct ufs_dev_fix ufs_fixups[] = { | |||
140 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), | 147 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), |
141 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | 148 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, |
142 | UFS_DEVICE_NO_FASTAUTO), | 149 | UFS_DEVICE_NO_FASTAUTO), |
150 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
151 | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), | ||
143 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, | 152 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, |
144 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | 153 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), |
145 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", | 154 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", |
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b89618f27725..6f6a209fdae0 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -4979,6 +4979,76 @@ out: | |||
4979 | return ret; | 4979 | return ret; |
4980 | } | 4980 | } |
4981 | 4981 | ||
4982 | /** | ||
4983 | * ufshcd_quirk_tune_host_pa_tactivate - Ensures that host PA_TACTIVATE is | ||
4984 | * less than device PA_TACTIVATE time. | ||
4985 | * @hba: per-adapter instance | ||
4986 | * | ||
4987 | * Some UFS devices require host PA_TACTIVATE to be lower than device | ||
4988 | * PA_TACTIVATE, we need to enable UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE quirk | ||
4989 | * for such devices. | ||
4990 | * | ||
4991 | * Returns zero on success, non-zero error value on failure. | ||
4992 | */ | ||
4993 | static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) | ||
4994 | { | ||
4995 | int ret = 0; | ||
4996 | u32 granularity, peer_granularity; | ||
4997 | u32 pa_tactivate, peer_pa_tactivate; | ||
4998 | u32 pa_tactivate_us, peer_pa_tactivate_us; | ||
4999 | u8 gran_to_us_table[] = {1, 4, 8, 16, 32, 100}; | ||
5000 | |||
5001 | ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_GRANULARITY), | ||
5002 | &granularity); | ||
5003 | if (ret) | ||
5004 | goto out; | ||
5005 | |||
5006 | ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_GRANULARITY), | ||
5007 | &peer_granularity); | ||
5008 | if (ret) | ||
5009 | goto out; | ||
5010 | |||
5011 | if ((granularity < PA_GRANULARITY_MIN_VAL) || | ||
5012 | (granularity > PA_GRANULARITY_MAX_VAL)) { | ||
5013 | dev_err(hba->dev, "%s: invalid host PA_GRANULARITY %d", | ||
5014 | __func__, granularity); | ||
5015 | return -EINVAL; | ||
5016 | } | ||
5017 | |||
5018 | if ((peer_granularity < PA_GRANULARITY_MIN_VAL) || | ||
5019 | (peer_granularity > PA_GRANULARITY_MAX_VAL)) { | ||
5020 | dev_err(hba->dev, "%s: invalid device PA_GRANULARITY %d", | ||
5021 | __func__, peer_granularity); | ||
5022 | return -EINVAL; | ||
5023 | } | ||
5024 | |||
5025 | ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE), &pa_tactivate); | ||
5026 | if (ret) | ||
5027 | goto out; | ||
5028 | |||
5029 | ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_TACTIVATE), | ||
5030 | &peer_pa_tactivate); | ||
5031 | if (ret) | ||
5032 | goto out; | ||
5033 | |||
5034 | pa_tactivate_us = pa_tactivate * gran_to_us_table[granularity - 1]; | ||
5035 | peer_pa_tactivate_us = peer_pa_tactivate * | ||
5036 | gran_to_us_table[peer_granularity - 1]; | ||
5037 | |||
5038 | if (pa_tactivate_us > peer_pa_tactivate_us) { | ||
5039 | u32 new_peer_pa_tactivate; | ||
5040 | |||
5041 | new_peer_pa_tactivate = pa_tactivate_us / | ||
5042 | gran_to_us_table[peer_granularity - 1]; | ||
5043 | new_peer_pa_tactivate++; | ||
5044 | ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE), | ||
5045 | new_peer_pa_tactivate); | ||
5046 | } | ||
5047 | |||
5048 | out: | ||
5049 | return ret; | ||
5050 | } | ||
5051 | |||
4982 | static void ufshcd_tune_unipro_params(struct ufs_hba *hba) | 5052 | static void ufshcd_tune_unipro_params(struct ufs_hba *hba) |
4983 | { | 5053 | { |
4984 | if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { | 5054 | if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { |
@@ -4989,6 +5059,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) | |||
4989 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE) | 5059 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE) |
4990 | /* set 1ms timeout for PA_TACTIVATE */ | 5060 | /* set 1ms timeout for PA_TACTIVATE */ |
4991 | ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10); | 5061 | ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10); |
5062 | |||
5063 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) | ||
5064 | ufshcd_quirk_tune_host_pa_tactivate(hba); | ||
4992 | } | 5065 | } |
4993 | 5066 | ||
4994 | /** | 5067 | /** |
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index eff8b5675575..23129d7b2678 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h | |||
@@ -123,6 +123,7 @@ | |||
123 | #define PA_MAXRXHSGEAR 0x1587 | 123 | #define PA_MAXRXHSGEAR 0x1587 |
124 | #define PA_RXHSUNTERMCAP 0x15A5 | 124 | #define PA_RXHSUNTERMCAP 0x15A5 |
125 | #define PA_RXLSTERMCAP 0x15A6 | 125 | #define PA_RXLSTERMCAP 0x15A6 |
126 | #define PA_GRANULARITY 0x15AA | ||
126 | #define PA_PACPREQTIMEOUT 0x1590 | 127 | #define PA_PACPREQTIMEOUT 0x1590 |
127 | #define PA_PACPREQEOBTIMEOUT 0x1591 | 128 | #define PA_PACPREQEOBTIMEOUT 0x1591 |
128 | #define PA_HIBERN8TIME 0x15A7 | 129 | #define PA_HIBERN8TIME 0x15A7 |
@@ -158,6 +159,9 @@ | |||
158 | #define VS_DEBUGOMC 0xD09E | 159 | #define VS_DEBUGOMC 0xD09E |
159 | #define VS_POWERSTATE 0xD083 | 160 | #define VS_POWERSTATE 0xD083 |
160 | 161 | ||
162 | #define PA_GRANULARITY_MIN_VAL 1 | ||
163 | #define PA_GRANULARITY_MAX_VAL 6 | ||
164 | |||
161 | /* PHY Adapter Protocol Constants */ | 165 | /* PHY Adapter Protocol Constants */ |
162 | #define PA_MAXDATALANES 4 | 166 | #define PA_MAXDATALANES 4 |
163 | 167 | ||