Loading drivers/scsi/ufs/ufshcd.c +109 −0 Original line number Diff line number Diff line Loading @@ -791,6 +791,32 @@ static const char *ufschd_clk_gating_state_to_string( } } static u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { /* HCI version < 2.0 supports UniPro 1.41 */ if (hba->ufs_version < UFSHCI_VERSION_20) return UFS_UNIPRO_VER_1_41; else return UFS_UNIPRO_VER_1_6; } static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) { /* * If both host and device support UniPro ver1.6 or later, PA layer * parameters tuning happens during link startup itself. * * We can manually tune PA layer parameters if either host or device * doesn't support UniPro ver 1.6 or later. But to keep manual tuning * logic simple, we will only do manual tuning if local unipro version * doesn't support ver1.6 or later. */ if (ufshcd_get_local_unipro_ver(hba) <= UFS_UNIPRO_VER_1_6) return true; else return false; } static void ufshcd_ungate_work(struct work_struct *work) { int ret; Loading Loading @@ -4891,6 +4917,88 @@ out: return err; } /** * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro * @hba: per-adapter instance * * PA_TActivate parameter can be tuned manually if UniPro version is less than * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce * the hibern8 exit latency. * * Returns zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba) { int ret = 0; u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate; if (!ufshcd_is_unipro_pa_params_tuning_req(hba)) return 0; ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(RX_MIN_ACTIVATETIME_CAPABILITY), &peer_rx_min_activatetime); if (ret) goto out; /* make sure proper unit conversion is applied */ tuned_pa_tactivate = ((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US) / PA_TACTIVATE_TIME_UNIT_US); ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), tuned_pa_tactivate); out: return ret; } /** * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro * @hba: per-adapter instance * * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY. * This optimal value can help reduce the hibern8 exit latency. * * Returns zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba) { int ret = 0; u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0; u32 max_hibern8_time, tuned_pa_hibern8time; ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HIBERN8TIME_CAPABILITY), &local_tx_hibern8_time_cap); if (ret) goto out; ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(RX_HIBERN8TIME_CAPABILITY), &peer_rx_hibern8_time_cap); if (ret) goto out; max_hibern8_time = max(local_tx_hibern8_time_cap, peer_rx_hibern8_time_cap); /* make sure proper unit conversion is applied */ tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US) / PA_HIBERN8_TIME_UNIT_US); ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), tuned_pa_hibern8time); out: return ret; } static void ufshcd_tune_unipro_params(struct ufs_hba *hba) { if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { ufshcd_tune_pa_tactivate(hba); ufshcd_tune_pa_hibern8time(hba); } } /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance Loading Loading @@ -4921,6 +5029,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) goto out; ufs_advertise_fixup_device(hba); ufshcd_tune_unipro_params(hba); if (!hba->is_init_prefetch) { ret = ufshcd_get_device_ref_clk(hba); Loading drivers/scsi/ufs/ufshci.h +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ enum { enum { UFSHCI_VERSION_10 = 0x00010000, UFSHCI_VERSION_11 = 0x00010100, UFSHCI_VERSION_20 = 0x00020000, }; /* Loading include/linux/scsi/ufs/unipro.h +19 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ /* * M-TX Configuration Attributes */ #define TX_HIBERN8TIME_CAPABILITY 0x000F #define TX_MODE 0x0021 #define TX_HSRATE_SERIES 0x0022 #define TX_HSGEAR 0x0023 Loading Loading @@ -46,8 +47,13 @@ #define RX_ENTER_HIBERN8 0x00A7 #define RX_BYPASS_8B10B_ENABLE 0x00A8 #define RX_TERMINATION_FORCE_ENABLE 0x0089 #define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F #define RX_HIBERN8TIME_CAPABILITY 0x0092 #define is_mphy_tx_attr(attr) (attr < RX_MODE) #define RX_MIN_ACTIVATETIME_UNIT_US 100 #define HIBERN8TIME_UNIT_US 100 /* * PHY Adpater attributes */ Loading Loading @@ -108,6 +114,9 @@ #define PA_STALLNOCONFIGTIME 0x15A3 #define PA_SAVECONFIGTIME 0x15A4 #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 /* PA power modes */ enum { FAST_MODE = 1, Loading Loading @@ -141,6 +150,16 @@ enum ufs_hs_gear_tag { UFS_HS_G3, /* HS Gear 3 */ }; enum ufs_unipro_ver { UFS_UNIPRO_VER_RESERVED = 0, UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */ UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */ UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */ UFS_UNIPRO_VER_MAX = 4, /* UniPro unsupported version */ /* UniPro version field mask in PA_LOCALVERINFO */ UFS_UNIPRO_VER_MASK = 0xF, }; /* * Data Link Layer Attributes */ Loading Loading
drivers/scsi/ufs/ufshcd.c +109 −0 Original line number Diff line number Diff line Loading @@ -791,6 +791,32 @@ static const char *ufschd_clk_gating_state_to_string( } } static u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { /* HCI version < 2.0 supports UniPro 1.41 */ if (hba->ufs_version < UFSHCI_VERSION_20) return UFS_UNIPRO_VER_1_41; else return UFS_UNIPRO_VER_1_6; } static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) { /* * If both host and device support UniPro ver1.6 or later, PA layer * parameters tuning happens during link startup itself. * * We can manually tune PA layer parameters if either host or device * doesn't support UniPro ver 1.6 or later. But to keep manual tuning * logic simple, we will only do manual tuning if local unipro version * doesn't support ver1.6 or later. */ if (ufshcd_get_local_unipro_ver(hba) <= UFS_UNIPRO_VER_1_6) return true; else return false; } static void ufshcd_ungate_work(struct work_struct *work) { int ret; Loading Loading @@ -4891,6 +4917,88 @@ out: return err; } /** * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro * @hba: per-adapter instance * * PA_TActivate parameter can be tuned manually if UniPro version is less than * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce * the hibern8 exit latency. * * Returns zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba) { int ret = 0; u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate; if (!ufshcd_is_unipro_pa_params_tuning_req(hba)) return 0; ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(RX_MIN_ACTIVATETIME_CAPABILITY), &peer_rx_min_activatetime); if (ret) goto out; /* make sure proper unit conversion is applied */ tuned_pa_tactivate = ((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US) / PA_TACTIVATE_TIME_UNIT_US); ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), tuned_pa_tactivate); out: return ret; } /** * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro * @hba: per-adapter instance * * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY. * This optimal value can help reduce the hibern8 exit latency. * * Returns zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba) { int ret = 0; u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0; u32 max_hibern8_time, tuned_pa_hibern8time; ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HIBERN8TIME_CAPABILITY), &local_tx_hibern8_time_cap); if (ret) goto out; ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(RX_HIBERN8TIME_CAPABILITY), &peer_rx_hibern8_time_cap); if (ret) goto out; max_hibern8_time = max(local_tx_hibern8_time_cap, peer_rx_hibern8_time_cap); /* make sure proper unit conversion is applied */ tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US) / PA_HIBERN8_TIME_UNIT_US); ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), tuned_pa_hibern8time); out: return ret; } static void ufshcd_tune_unipro_params(struct ufs_hba *hba) { if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { ufshcd_tune_pa_tactivate(hba); ufshcd_tune_pa_hibern8time(hba); } } /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance Loading Loading @@ -4921,6 +5029,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) goto out; ufs_advertise_fixup_device(hba); ufshcd_tune_unipro_params(hba); if (!hba->is_init_prefetch) { ret = ufshcd_get_device_ref_clk(hba); Loading
drivers/scsi/ufs/ufshci.h +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ enum { enum { UFSHCI_VERSION_10 = 0x00010000, UFSHCI_VERSION_11 = 0x00010100, UFSHCI_VERSION_20 = 0x00020000, }; /* Loading
include/linux/scsi/ufs/unipro.h +19 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ /* * M-TX Configuration Attributes */ #define TX_HIBERN8TIME_CAPABILITY 0x000F #define TX_MODE 0x0021 #define TX_HSRATE_SERIES 0x0022 #define TX_HSGEAR 0x0023 Loading Loading @@ -46,8 +47,13 @@ #define RX_ENTER_HIBERN8 0x00A7 #define RX_BYPASS_8B10B_ENABLE 0x00A8 #define RX_TERMINATION_FORCE_ENABLE 0x0089 #define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F #define RX_HIBERN8TIME_CAPABILITY 0x0092 #define is_mphy_tx_attr(attr) (attr < RX_MODE) #define RX_MIN_ACTIVATETIME_UNIT_US 100 #define HIBERN8TIME_UNIT_US 100 /* * PHY Adpater attributes */ Loading Loading @@ -108,6 +114,9 @@ #define PA_STALLNOCONFIGTIME 0x15A3 #define PA_SAVECONFIGTIME 0x15A4 #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 /* PA power modes */ enum { FAST_MODE = 1, Loading Loading @@ -141,6 +150,16 @@ enum ufs_hs_gear_tag { UFS_HS_G3, /* HS Gear 3 */ }; enum ufs_unipro_ver { UFS_UNIPRO_VER_RESERVED = 0, UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */ UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */ UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */ UFS_UNIPRO_VER_MAX = 4, /* UniPro unsupported version */ /* UniPro version field mask in PA_LOCALVERINFO */ UFS_UNIPRO_VER_MASK = 0xF, }; /* * Data Link Layer Attributes */ Loading