diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8222653fb2c2..ae2e1f9c58d6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6581,12 +6581,11 @@ out: return icc_level; } -static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba) +static void ufshcd_init_icc_levels(struct ufs_hba *hba) { int ret; int buff_len = hba->desc_size.pwr_desc; u8 *desc_buf; - u32 icc_level; desc_buf = kmalloc(buff_len, GFP_KERNEL); if (!desc_buf) @@ -6600,17 +6599,20 @@ static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba) goto out; } - icc_level = ufshcd_find_max_sup_active_icc_level(hba, desc_buf, - buff_len); - dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, icc_level); + hba->init_prefetch_data.icc_level = + ufshcd_find_max_sup_active_icc_level(hba, + desc_buf, buff_len); + dev_dbg(hba->dev, "%s: setting icc_level 0x%x", + __func__, hba->init_prefetch_data.icc_level); ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, &icc_level); + QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, + &hba->init_prefetch_data.icc_level); if (ret) dev_err(hba->dev, "%s: Failed configuring bActiveICCLevel = %d ret = %d", - __func__, icc_level, ret); + __func__, hba->init_prefetch_data.icc_level , ret); out: kfree(desc_buf); @@ -7105,14 +7107,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) } } - /* - * bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec) - * and for removable UFS card as well, hence always set the parameter. - * Note: Error handler may issue the device reset hence resetting - * bActiveICCLevel as well so it is always safe to set this here. - */ - ufshcd_set_active_icc_lvl(hba); - /* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; @@ -7132,6 +7126,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) QUERY_FLAG_IDN_PWR_ON_WPE, &flag)) hba->dev_info.f_power_on_wp_en = flag; + if (!hba->is_init_prefetch) + ufshcd_init_icc_levels(hba); + /* Add required well known logical units to scsi mid layer */ if (ufshcd_scsi_add_wlus(hba)) goto out; @@ -7156,6 +7153,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) pm_runtime_put_sync(hba->dev); } + if (!hba->is_init_prefetch) + hba->is_init_prefetch = true; + out: /* * If we failed to initialize the device or the device is not diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 94311bb1dd2c..1a6cd23a15fd 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -440,6 +440,15 @@ struct ufs_clk_scaling { bool is_suspended; }; +/** + * struct ufs_init_prefetch - contains data that is pre-fetched once during + * initialization + * @icc_level: icc level which was read during initialization + */ +struct ufs_init_prefetch { + u32 icc_level; +}; + #define UFS_ERR_REG_HIST_LENGTH 8 /** * struct ufs_err_reg_hist - keeps history of errors @@ -531,6 +540,8 @@ struct ufs_stats { * @intr_mask: Interrupt Mask Bits * @ee_ctrl_mask: Exception event control mask * @is_powered: flag to check if HBA is powered + * @is_init_prefetch: flag to check if data was pre-fetched in initialization + * @init_prefetch_data: data pre-fetched during initialization * @eh_work: Worker to handle UFS errors that require s/w attention * @eeh_work: Worker to handle exception events * @errors: HBA errors @@ -694,6 +705,8 @@ struct ufs_hba { u32 intr_mask; u16 ee_ctrl_mask; bool is_powered; + bool is_init_prefetch; + struct ufs_init_prefetch init_prefetch_data; /* Work Queues */ struct work_struct eh_work;