scsi: ufs: ufs-pci: Fix Intel LKF link stability
Intel LKF can experience link errors. Make fixes to increase link
stability, especially when switching to high speed modes.
Link: https://lore.kernel.org/r/20210831145317.26306-1-adrian.hunter@intel.com
Fixes: b2c57925df
("scsi: ufs: ufs-pci: Add support for Intel LKF")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
04c260bdae
commit
1cbc9ad3ee
@ -128,6 +128,81 @@ static int ufs_intel_link_startup_notify(struct ufs_hba *hba,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufs_intel_set_lanes(struct ufs_hba *hba, u32 lanes)
|
||||
{
|
||||
struct ufs_pa_layer_attr pwr_info = hba->pwr_info;
|
||||
int ret;
|
||||
|
||||
pwr_info.lane_rx = lanes;
|
||||
pwr_info.lane_tx = lanes;
|
||||
ret = ufshcd_config_pwr_mode(hba, &pwr_info);
|
||||
if (ret)
|
||||
dev_err(hba->dev, "%s: Setting %u lanes, err = %d\n",
|
||||
__func__, lanes, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba,
|
||||
enum ufs_notify_change_status status,
|
||||
struct ufs_pa_layer_attr *dev_max_params,
|
||||
struct ufs_pa_layer_attr *dev_req_params)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (status) {
|
||||
case PRE_CHANGE:
|
||||
if (ufshcd_is_hs_mode(dev_max_params) &&
|
||||
(hba->pwr_info.lane_rx != 2 || hba->pwr_info.lane_tx != 2))
|
||||
ufs_intel_set_lanes(hba, 2);
|
||||
memcpy(dev_req_params, dev_max_params, sizeof(*dev_req_params));
|
||||
break;
|
||||
case POST_CHANGE:
|
||||
if (ufshcd_is_hs_mode(dev_req_params)) {
|
||||
u32 peer_granularity;
|
||||
|
||||
usleep_range(1000, 1250);
|
||||
err = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_GRANULARITY),
|
||||
&peer_granularity);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufs_intel_lkf_apply_dev_quirks(struct ufs_hba *hba)
|
||||
{
|
||||
u32 granularity, peer_granularity;
|
||||
u32 pa_tactivate, peer_pa_tactivate;
|
||||
int ret;
|
||||
|
||||
ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_GRANULARITY), &granularity);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_GRANULARITY), &peer_granularity);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE), &pa_tactivate);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_TACTIVATE), &peer_pa_tactivate);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (granularity == peer_granularity) {
|
||||
u32 new_peer_pa_tactivate = pa_tactivate + 2;
|
||||
|
||||
ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE), new_peer_pa_tactivate);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define INTEL_ACTIVELTR 0x804
|
||||
#define INTEL_IDLELTR 0x808
|
||||
|
||||
@ -351,6 +426,7 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba)
|
||||
struct ufs_host *ufs_host;
|
||||
int err;
|
||||
|
||||
hba->nop_out_timeout = 200;
|
||||
hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
|
||||
hba->caps |= UFSHCD_CAP_CRYPTO;
|
||||
err = ufs_intel_common_init(hba);
|
||||
@ -381,6 +457,8 @@ static struct ufs_hba_variant_ops ufs_intel_lkf_hba_vops = {
|
||||
.exit = ufs_intel_common_exit,
|
||||
.hce_enable_notify = ufs_intel_hce_enable_notify,
|
||||
.link_startup_notify = ufs_intel_link_startup_notify,
|
||||
.pwr_change_notify = ufs_intel_lkf_pwr_change_notify,
|
||||
.apply_dev_quirks = ufs_intel_lkf_apply_dev_quirks,
|
||||
.resume = ufs_intel_resume,
|
||||
.device_reset = ufs_intel_device_reset,
|
||||
};
|
||||
|
@ -4776,7 +4776,7 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
|
||||
mutex_lock(&hba->dev_cmd.lock);
|
||||
for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
|
||||
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
|
||||
NOP_OUT_TIMEOUT);
|
||||
hba->nop_out_timeout);
|
||||
|
||||
if (!err || err == -ETIMEDOUT)
|
||||
break;
|
||||
@ -9483,6 +9483,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
|
||||
hba->host = host;
|
||||
hba->dev = dev;
|
||||
hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL;
|
||||
hba->nop_out_timeout = NOP_OUT_TIMEOUT;
|
||||
INIT_LIST_HEAD(&hba->clk_list_head);
|
||||
spin_lock_init(&hba->outstanding_lock);
|
||||
|
||||
|
@ -858,6 +858,7 @@ struct ufs_hba {
|
||||
/* Device management request data */
|
||||
struct ufs_dev_cmd dev_cmd;
|
||||
ktime_t last_dme_cmd_tstamp;
|
||||
int nop_out_timeout;
|
||||
|
||||
/* Keeps information of the UFS device connected to this host */
|
||||
struct ufs_dev_info dev_info;
|
||||
|
Loading…
Reference in New Issue
Block a user